[OH3] Main UI - New „main_widget“ - development and testing [deprecated]

Hey,

All (hmerk, Dimitris and me) Are working behind the scenes at the moment. Focus is actual at menu and adding widgets.

2 Likes

Hi.
I am posting my widget screenshots for my radiators and my shutters.
They are copy paste and modified from other users. Just for the people to get an idea if they want tk adopt somethings.


2 Likes

They’re so nice! This should be the spirit of community,nice job man!
You’d better to share the yaml for anyone wants it, but better to open a new topic :wink:

No probs - was just exciting watching all the development happening in real time - was like a podcast!

1 Like

Hi @JustinG,

lots of things happen behind the scene - next version will be shown soon - but as you know me - there are still some questions open.

At the moment I am struggling with the height of f7-block.

We use a more or less generic template to create the different cards.

The template contains of three blocks. Header and Footer are absolutely sized (50px and 60px). But the content is at the moment depending of it content. The radiator card uses a oh-trendline and therefore the height is a bit more height then for example the roller-shutter-card that has no trendline.

How could we achieve that the card in sum has every time the same size - equal if there is a trend line or any other component? And is there a chance to make header and footer also relative height?

uid: main_widget_RadiatorControl_Card
tags: []
props:
  parameters:
    - description: Title of the card
      label: Title
      name: Title
      required: false
      type: TEXT
    - context: item
      description: Temperature Equipment Group
      label: Temperature Equipment Group
      name: groupItem
      required: false
      type: TEXT
timestamp: Oct 21, 2022, 2:41:03 PM
component: f7-card
config:
  style:
    background: "#F7F7F7"
    border-bottom-left-radius: var(--f7-card-expandable-border-radius)
    border-bottom-right-radius: var(--f7-card-expandable-border-radius)
    border-top-left-radius: var(--f7-card-expandable-border-radius)
    border-top-right-radius: var(--f7-card-expandable-border-radius)
    padding: 0px
    margin: 15px
slots:
  default:
    - component: f7-block
      config:
        style:
          align-items: center
          background: transparent
          display: flex
          flex-direction: row
          height: 60px
      slots:
        default:
          - component: oh-icon
            config:
              icon: iconify:ion:flame-sharp
              style:
                color: rgb(106,106,106)
                padding-right: 15px
              width: 40px
          - component: f7-row
            config:
              style:
                display: flex
                flex-direction: column
                flex-wrap: nowrap
            slots:
              default:
                - component: oh-repeater
                  config:
                    fetchMetadata: semantics,metadata,listWidget
                    filter: "(loop.title.groupNames.indexOf(props.groupItem) >= 0) ? true : false"
                    for: title
                    itemTags: Measurement,Temperature
                    sourceType: itemsWithTags
                  slots:
                    default:
                      - component: Label
                        config:
                          style:
                            font-size: 14px
                            font-weight: 400
                            padding-top: 10px
                          text: =props.Title
                - component: f7-row
                  config:
                    style:
                      display: flex
                      flex-direction: row
                  slots:
                    default:
                      - component: oh-repeater
                        config:
                          fetchMetadata: semantics,metadata,listWidget
                          filter: "(loop.tempItem.groupNames.indexOf(props.groupItem) >= 0) ? true : false"
                          for: tempItem
                          itemTags: Measurement,Temperature
                          sourceType: itemsWithTags
                        slots:
                          default:
                            - component: f7-chip
                              config:
                                style:
                                  background-color: "#6a6a6a"
                                  color: white
                                  font-size: 16px
                                  font-weight: 200
                                  justify-content: flex-end
                                text: "=items[loop.tempItem.name].displayState ? items[loop.tempItem.name].displayState : items[loop.tempItem.name].state"
                      - component: oh-repeater
                        config:
                          fetchMetadata: semantics,metadata,listWidget
                          filter: "(loop.setpointItem.groupNames.indexOf(props.groupItem) >= 0) ? true : false"
                          for: setpointItem
                          itemTags: Setpoint,Temperature
                          sourceType: itemsWithTags
                        slots:
                          default:
                            - component: f7-chip
                              config:
                                style:
                                  background: none
                                  color: red
                                  font-size: 18px
                                  font-weight: 300
                                text: "=items[loop.setpointItem.name].displayState ? items[loop.setpointItem.name].displayState : items[loop.setpointItem.name].state"
    - component: f7-block
      config:
        style:
          align-items: center
          background: transparent
          display: flex
          flex-direction: row
      slots:
        default:
          - component: oh-repeater
            config:
              fetchMetadata: semantics,metadata,listWidget
              filter: "(loop.tempItem.groupNames.indexOf(props.groupItem) >= 0) ? true : false"
              for: tempItem
              itemTags: Measurement,Temperature
              sourceType: itemsWithTags
            slots:
              default:
                - component: oh-trend
                  config:
                    trendGradient:
                      - "#E74239"
                    trendItem: =loop.tempItem.name
                    trendSampling: 5
          - component: oh-repeater
            config:
              fetchMetadata: semantics,metadata,listWidget
              filter: "(loop.setpointItem.groupNames.indexOf(props.groupItem) >= 0) ? true : false"
              for: setpointItem
              itemTags: Setpoint,Temperature
              sourceType: itemsWithTags
            slots:
              default:
                - component: f7-row
                  config:
                    style:
                      align-self: flex-end
                      display: flex
                      flex: 1 1 auto
                      flex-direction: row
                      flex-wrap: nowrap
                      justify-content: flex-end
                  slots:
                    default:
                      - component: oh-button
                        config:
                          action: command
                          actionCommand: =Number(items[loop.setpointItem.name].state.split(' ')[0]) + 0.5
                          actionItem: =loop.setpointItem.name
                          iconColor: "#E74239"
                          iconF7: arrow_up_circle
                          iconSize: 35
                          style:
                            align-self: flex-end
                            background: transparent
                            display: flex
                            flex-direction: row
                            flex-wrap: nowrap
                            height: 35px
                            justify-content: flex-end
                      - component: oh-button
                        config:
                          action: command
                          actionCommand: =Number(items[loop.setpointItem.name].state.split(' ')[0]) - 0.5
                          actionItem: =loop.setpointItem.name
                          iconColor: "#E74239"
                          iconF7: arrow_down_circle
                          iconSize: 35
                          style:
                            align-self: flex-end
                            background: transparent
                            display: flex
                            flex-direction: row
                            flex-wrap: nowrap
                            height: 35px
                            justify-content: flex-end
    - component: f7-block
      config:
        style:
          --f7-card-footer-border-color: transparent
          align-items: center
          background: "#F2F2F2"
          border-radius: 0 0 var(--f7-card-expandable-border-radius) var(--f7-card-expandable-border-radius)
          display: flex
          flex-direction: row
          height: 50px
      slots:
        default:
          - component: oh-repeater
            config:
              fetchMetadata: semantics,metadata,listWidget
              filter: '((loop.modeItem.groupNames.indexOf(props.groupItem) >= 0) && (loop.modeItem.type=="String")) ? true : false'
              for: modeItem
              itemTags: Control,Temperature
              sourceType: itemsWithTags
            slots:
              default:
                - component: f7-block
                  config:
                    style:
                      display: flex
                      flex-direction: row
                  slots:
                    default:
                      - component: oh-link
                        config:
                          action: options
                          actionItem: =loop.modeItem.name
                        slots:
                          default:
                            - component: f7-chip
                              config:
                                text: "=items[loop.modeItem.name].displayState ? items[loop.modeItem.name].displayState : items.items[loop.modeItem.name].state"

uid: main_widget_Rollershutter_Card
tags: []
props:
  parameters:
    - description: Title of the card
      label: Title
      name: Title
      required: false
      type: TEXT
    - context: item
      description: Item to control
      label: Rollershutter Item
      name: RollerItem
      required: true
      type: TEXT
timestamp: Oct 21, 2022, 8:12:02 PM
component: f7-card
config:
  style:
    background: "#F7F7F7"
    border-bottom-left-radius: var(--f7-card-expandable-border-radius)
    border-bottom-right-radius: var(--f7-card-expandable-border-radius)
    border-top-left-radius: var(--f7-card-expandable-border-radius)
    border-top-right-radius: var(--f7-card-expandable-border-radius)
    padding: 0px
    margin: 15px
slots:
  default:
    - component: f7-block
      config:
        style:
          align-items: center
          background: transparent
          display: flex
          flex-direction: row
          height: 60px
      slots:
        default:
          - component: oh-icon
            config:
              icon: iconify:mdi:window-shutter-alert
              style:
                color: rgb(106,106,106)
                padding-right: 15px
              width: 40px
          - component: f7-row
            config:
              style:
                display: flex
                flex-direction: column
                flex-wrap: nowrap
            slots:
              default:
                - component: Label
                  config:
                    style:
                      font-size: 14px
                      font-weight: 400
                      padding-top: 10px
                    text: =props.Title
                - component: f7-row
                  config:
                    style:
                      display: flex
                      flex-direction: row
                  slots:
                    default:
                      - component: f7-chip
                        config:
                          style:
                            background-color: "#6a6a6a"
                            color: white
                            font-size: 16px
                            font-weight: 200
                            justify-content: flex-end
                          text: =items[props.RollerItem].state + "% " + " close"
    - component: f7-block
      config:
        style:
          align-items: center
          background: transparent
          display: flex
          flex-direction: row
          min-height: 81px
      slots:
        default:
          - component: f7-row
            config:
              style:
                align-self: flex-end
                display: flex
                flex: 1 1 auto
                flex-direction: row
                flex-wrap: nowrap
                justify-content: flex-end
            slots:
              default:
                - component: oh-button
                  config:
                    action: command
                    actionCommand: UP
                    actionItem: =props.RollerItem
                    iconColor: "#E74239"
                    iconF7: arrow_up_circle
                    iconSize: 35
                    style:
                      align-self: flex-end
                      background: transparent
                      display: flex
                      flex-direction: row
                      flex-wrap: nowrap
                      height: 35px
                      justify-content: flex-end
                - component: oh-button
                  config:
                    action: command
                    actionCommand: STOP
                    actionItem: =props.RollerItem
                    iconColor: "#E74239"
                    iconF7: stop_circle
                    iconSize: 35
                    style:
                      align-self: flex-end
                      background: transparent
                      display: flex
                      flex-direction: row
                      flex-wrap: nowrap
                      height: 35px
                      justify-content: flex-end
                - component: oh-button
                  config:
                    action: command
                    actionCommand: DOWN
                    actionItem: =props.RollerItem
                    iconColor: "#E74239"
                    iconF7: arrow_down_circle
                    iconSize: 35
                    style:
                      align-self: flex-end
                      background: transparent
                      display: flex
                      flex-direction: row
                      flex-wrap: nowrap
                      height: 35px
                      justify-content: flex-end
    - component: f7-block
      config:
        style:
          --f7-card-footer-border-color: transparent
          align-items: center
          background: "#F2F2F2"
          border-radius: 0 0 var(--f7-card-expandable-border-radius) var(--f7-card-expandable-border-radius)
          display: flex
          flex-direction: row
          height: 50px
      slots:
        default:
          - component: Label
            config:
              style:
                color: white
                position: absolute
                top: 5%
              text: "Preset positions:"
    - component: oh-button
      config:
        action: command
        actionCommand: UP
        actionItem: =(props.RollerItem)
        class:
          - margin
          - display-flex
          - flex-direction-column
        round: true
        style:
          background: '=items[props.RollerItem].state == "0" ? "teal" : "gray"'
          color: white
          height: 24px
          left: 20%
          position: absolute
          top: 63%
          width: 10px
          z-index: 98
        text: "0"
    - component: oh-button
      config:
        action: command
        actionCommand: 50
        actionItem: =(props.RollerItem)
        class:
          - margin
          - display-flex
          - flex-direction-column
        round: true
        style:
          background: '=items[props.RollerItem].state == "50" ? "teal" : "gray"'
          color: white
          height: 24px
          left: 33%
          position: absolute
          top: 63%
          width: 10px
          z-index: 98
        text: 50
    - component: oh-button
      config:
        action: command
        actionCommand: 75
        actionItem: =(props.RollerItem)
        class:
          - margin
          - display-flex
          - flex-direction-column
        round: true
        style:
          background: '=items[props.RollerItem].state == "75" ? "teal" : "gray"'
          color: white
          height: 24px
          position: absolute
          right: 33%
          top: 63%
          width: 10px
          z-index: 98
        text: 75
    - component: oh-button
      config:
        action: command
        actionCommand: DOWN
        actionItem: =(props.RollerItem)
        class:
          - margin
          - display-flex
          - flex-direction-column
        round: true
        style:
          background: '=items[props.RollerItem].state == "100" ? "teal" : "gray"'
          color: white
          height: 24px
          position: absolute
          right: 20%
          top: 63%
          width: 10px
          z-index: 98
        text: 100


See my other answer here for an explanation if you are trying to use % and not getting the results you expect:

Of course, the f7-card is just a div container with fancy card style, so it can use flexbox styling and if you set the flex parameter on each of the f7-blocks to the ratios that you want for the different sections you get relative scaling of the header and footer.

You can set a height value in the style of the card (which, in fact you will want to do for relative sizing of the header and footer, anyway). What I would recommend is to use a css variable for it. You can set a variable in the main widget, and reference that variable in any of the other widgets inside the main widget just fine.

Could you describe this approach a bit further? It sounds really interesting but I think I did not get you right.

Lets say this simple main-widget:

uid: main_widget_test_var
tags: []
props:
  parameters:
    - description: Set default color for Text
      label: Text color
      name: textColor
      required: false
      type: TEXT
timestamp: Oct 22, 2022, 7:35:59 AM
component: f7-block
config:
  style:
    --f7-button-text-color: "#8c8c8c"
    --menu-text-color: '= (!props.textColor) ? (themeOptions.dark=="light")? black : white : props.textColor'
    --opmw-menu-text-color: =(themeOptions.dark=="light")?("#8C8C8C"):("#848484")
    background: =(themeOptions.dark=="light") ? ("white"):("black")
    display: flex
    flex-direction: column
    height: calc(100vh - var(--f7-toolbar-height) - var(--f7-safe-area-bottom) - var(--f7-safe-area-top))
    justify-content: space-between
    margin: 0
    padding: 0
    width: 100%
  stylesheet: >
    .widget_height {
      height: 500px;
    } 
slots:
  default:
    - component: widget:test_card
      config:
        Title: =props.Title
        class: widget_height

I defined the css-class widget_height and try to allocate it to the nested widget “test_card”.

Is this what you meant? If so - could you have a look why it does not work? I fear that the test_card could nothing do with this class. But then I perhaps did not understand you right…

And here the test_card.

uid: test_card
tags: []
props:
  parameters:
    - description: A text prop
      label: Prop 1
      name: titel
      required: false
      type: TEXT
    - context: item
      description: An item to control
      label: Item
      name: item
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Oct 22, 2022, 7:34:46 AM
component: f7-card
config:
  title: '=(props.item) ? "State of " + props.item : "Set props to test!"'
  footer: =props.prop1
  content: =items[props.item].displayState || items[props.item].state

This doesn’t work because the class is not passed to the card widget. When you add a child widget using - component: widget:widget name the only config options that get used are the ones that are defined in the widget’s parameters. You don’t have a class parameter, so the class configuration gets ignored. You can easily set a class parameter and then add class: =props.class to the base card in the widget.

However, I wasn’t talking about using css classes, I meant using css variables: the variables that are defined in the style object that start with two dashes (e.g.:

--opmw-menu-text-color: =(themeOptions.dark=="light")?("#8C8C8C"):("#848484")

In this case you would make up a new variable, something like --opmw-card-height and set that to your desired value:

--opmw-card-height: 500px

Then you use that in base card of the child widget with the css var() function:

style:
  height: var(--opmw-card-height)

Edit: Please note that when you do this, the card will not look correct when viewed on it’s own, because it cannot get the correct variable value unless is it embedded in the main widget.

ah thank you! Much clearer now - will try this!

Hi @JustinG

As always :slight_smile: Solving one problem another occurs :wink:

I try to use Stylesheets as much as possible. But in the following example only one of the css-classes work (the top_block). Could you please have, once again a look, why the other both classes are ignored?

uid: main_widget_Rollershutter_Card
tags: []
props:
  parameters:
    - description: Title of the card
      label: Title
      name: Title
      required: false
      type: TEXT
    - context: item
      description: Item to control
      label: Rollershutter Item
      name: RollerItem
      required: true
      type: TEXT
timestamp: Oct 22, 2022, 9:24:04 AM
component: f7-card
config:
  style:

    min-height: 191px
    
  stylesheet: >
    .base_card {
          background: red;
          border-bottom-left-radius: var(--f7-card-expandable-border-radius);
          border-bottom-right-radius: var(--f7-card-expandable-border-radius);
          border-top-left-radius: var(--f7-card-expandable-border-radius);
          border-top-right-radius: var(--f7-card-expandable-border-radius);
          margin: 15px;
          padding: 0px;
          min-height: 191px;
          
    } 
    
    .top_block {
          align-items: center;
          background: transparent;
          display: flex;
          flex-direction: row;
          height: 32%;
          min-height: 60px;
          background: yellow;
    } 
    
    .top_icon {
          color: rgb(106,106,106);
          padding-right: 15px;
          background: blue;
          
    } 
  class: base_card    
slots:
  default:
    - component: f7-block
      config:
        class: top_block
      slots:
        default:
          - component: oh-icon
            config:
              icon: iconify:mdi:window-shutter-alert
              class: top_icon
              width: 40px

Two different reasons:

  1. The top-icon class styling are ignored because the oh-image is one of the few components that doesn’t actually take the class property. It’s not passed from the yaml to the html element, the icon doesn’t have the class and therefore doesn’t get those style directives. The solution to this is to but the oh-icon inside it’s own container which can hold a class and then use a css selector in the style sheet that target the child elements of the class instead of the class element itself.

  2. For the base_card class, that is actually a class that is assigned to the f7-card but the way the stylesheets are implemented, they do not impact the element they are on, only the child elements. So if you put the stylesheet with .base_card directives in an f7-block and put the card with that class inside the block then you will see that the directives are applied.

Hi,
I follow your project with great interest.
I’m eeger to see what’s coming next. In the meantime I think I can prepare my config. What guidelines can I follow to build the right semantic modell for your work?

Cheers
Chris

Thnks for your interest. We know that our documentation ist still not sufficient. This will hopefully change with the next version coming soon.

To answer your question, here are the basic prerequisits :

  • Model needs to be structured in floors and rooms
  • No additional tags needed any more
  • All equipment has to be grouped on it’s own, so if having 2 lights in a room , you need to have 2 groups [Group → Equipment → Lightbulb].
  • Lights : Simple light just needs a switch item in the group. Dimmer (Brightness channel) and Colorpicker are optional
  • Blinds : Basically only Rollershutter item needed. Upcoming version will additionaly have support for a mode Switch and 4 DateTime items. This will be commpletey documented in the RollershutterCard Topic.
  • RadiatorControl: A bit more complex, as we need to determine ambient temperature and target temperature. Therefore you need the following items in the group:
    • [Number:]Temperature [Measurement/Temperature] → Ambient Temperature
    • [Number:] Temperature [Setpoint/Temperature] → Target Temperature
    • String [Control/Temperature] → Mode Item
  • Scenes : Scenes Group needs to be set in main_widget settings. Then you only need several switch items in that group.
  • HVAC: Will document later today.
  • Security: Will document later today, as this is even more commplex.

Thank you hmerk!

If I understand it right, is my setup correct?

Equipment group seems to be correct.

Switch:

Dimmer:

Color:

1 Like

Ready when you are :heartbeat:

Ready for what ???

In other words I think I modified my model to your needs and now I am ready to check out the next release.
Didn’t wanted to bully you hmerk. Sorry for that.

Have a good day!

No problem,
was just thinking if there was something from my side you were waiting for.
Hope to deploy next updates over the weekend. Need to find time for documentation.

@All - A new version has just been published for testing.

Big changes :

  • Simplification of menu useage
  • rooms and floors cards are now combined in “FloorsAndRooms”
  • rework of rollershutter card with some added features like time control.

Happy testing :wink: