Try to create an universal widget using oh-repeater, with itemsInGroup and color in lines

Hello Community,

in my environment I have a lot of items organized in groups. The items are Numbers, Number:Temperature or Number:Power etc…

Example for 2 items for “heating”. The measures room temperature lcn_Temp_… and the expected room temperature lcn_SetTe_…

Group           gHeizung_Soll               "Heizung Soll"                  <temperature>   (EG_Technik)        ["Equipment"]
Group           gHeizung_Ist                "Heizung Ist"                   <temperature>   (EG_Technik)        ["Equipment"]

Number              lcn_SetTe_OG_Gaeste          "Hz Gaeste" <temperature>   (OG_Gaeste,gHeizung_Soll)   ["Temperature","Setpoint"]  
{ channel="lcn:module:bus:S000M220:rvarsetpoint#1",
    widget    ="oh-stepper-card"[ title="Gaeste", min=16, max=24, step=0.5, icon="oh:temperature" ], 
    listWidget="oh-stepper-item"[ title="Gaeste", min=16, max=24, step=0.5, icon="oh:temperature" ],
    cellWidget="oh-stepper-cell"[ title="Gaeste", min=16, max=24, step=0.5, icon="oh:temperature" ], 
    autoupdate="false"  
}
Number:Temperature  lcn_Temp_OG_Gaeste          "Hz Gaeste Ist"             <temperature> (OG_Gaeste,gHeizung_Ist)  ["Temperature","Measurement"]
{ channel="lcn:module:bus:S000M220:variable#2", 
    stateDescription=" "[ pattern="%.1f °C"] 
}

Now I build my simple widget, which has two properties. A title and the name of the group. I will use this widget in different pages as an universal widget.

uid: 0_widget_number
tags: []
props:
  parameters:
    - description: Small title on top of the card
      label: Title
      name: title
      required: false
      type: TEXT
    - context: item
      description: Which group you will see
      label: Group
      name: GroupName
      required: false
      type: TEXT
  parameterGroups: []
timestamp: May 13, 2025, 5:42:51 PM
component: f7-card
config:
  title: "=props.title ? props.title : ''"
slots:
  content:
    - component: oh-list-card
      slots:
        default:
          - component: oh-repeater
            config:
              filter: =(loop.item.type == "Number" && parseFloat(loop.item.state) > 0)
              for: item
              groupItem: =props.GroupName
              sourceType: itemsInGroup
            slots:
              default:
                - component: f7-row
                  slots:
                    default:
                      - component: f7-col
                        config:
                          style:
                            text-align: left
                        slots:
                          default:
                            - component: Label
                              config:
                                text: =loop.item.label
                      - component: f7-col
                        config:
                          style:
                            text-align: right
                        slots:
                          default:
                            - component: Label
                              config:
                                text: =loop.item.state
                                style:
                                  color: |
                                    =loop.item.state < 19 ? 'blue' :
                                     loop.item.state < 21 ? 'green' :
                                     loop.item.state < 23 ? 'orange' : 'black'
                                  background-color: |
                                    =loop.item.state < 19 ? 'lightgreen' :
                                     loop.item.state < 21 ? 'lightblue' :
                                     loop.item.state < 23 ? 'yellow' : 'red'
                                  padding: 1px

My problem is, how to deal with the unit, if an item is e.g. “Number:Temperature”.

Any ideas how to deal with these “unit” ?

Best regards
Rafl

The loop.item.state is always a String. So first of all you need to get the numeric state: Widget Expressions & Variables | openHAB.

Calling .numericState should strip off the unit.

    =loop.item.numericState < 19 ? 'blue'

I’m pretty sure numericState is available in the repeater card.

Hi Rich,
it doesn’t fix it.

I replaced the last lines “state” <> “numericState”. But than the left “Heizung Soll” look like the right “Heizung Ist”… background red, text black.

Keep in mind, I have openhab 4.3.2 running.

thx Ralf

                                  color: >
                                    =loop.item.numericState < 19 ? 'blue' :
                                     loop.item.numericState < 21 ? 'green' :
                                     loop.item.numericState < 23 ? 'orange' : 'black'
                                  background-color: >
                                    =loop.item.numericState < 19 ? 'lightgreen':
                                     loop.item.numericState < 21 ? 'lightblue' :
                                     loop.item.numericState < 23 ? 'yellow' : 'red'

In that case, you’ll have to parse the loop.item.state into a number. I believe parseInt() and parseFloat() simply stop when they run into a non-numeric character, which will serve to strip off the units.

that’s the solution…ok, there is something addition to do with the colors :wink:

Again the full widget:

uid: 0_widget_number
tags: []
props:
  parameters:
    - description: Title on top
      label: Title
      name: title
      required: false
      type: TEXT
    - context: item
      description: Which group you will see
      label: Group
      name: GroupName
      required: false
      type: TEXT
    - context: item
      description: low value - e.g. 15
      label: low value
      name: valueOne
      required: true
    - context: item
      description: medium 1 value - e.g. 20
      label: medium 1 value
      name: valueTwo
      required: true
    - context: item
      description: medium 2 value - e.g. 25
      label: medium 2 value
      name: valueThree
      required: true
    - context: item
      description: Background color for value1 with '#7cf295' or e.g. 'lightblue'
      label: color low
      name: colorOne
      required: false
    - context: item
      description: Background color for value2 with '#fafaa5' or e.g. 'lightgreen'
      label: color medium 1
      name: colorTwo
      required: false
    - context: item
      description: Background color for Value3 with '#fca65b' or e.g. 'yellow'
      label: color medium 2
      name: colorThree
      required: false
    - context: item
      description: Background color for Value3 with '#fa8f5a' or e.g. 'violet'
      label: color high
      name: colorFour
      required: false
  parameterGroups: []
timestamp: May 13, 2025, 11:01:33 PM
component: f7-card
config:
  title: "=props.title ? props.title : ''"
slots:
  content:
    - component: oh-list-card
      slots:
        default:
          - component: oh-repeater
            config:
              filter: =(loop.item.type == "Number" && parseFloat(loop.item.state) > 0)
              for: item
              groupItem: =props.GroupName
              sourceType: itemsInGroup
            slots:
              default:
                - component: f7-row
                  slots:
                    default:
                      - component: f7-col
                        config:
                          style:
                            text-align: left
                        slots:
                          default:
                            - component: Label
                              config:
                                text: =loop.item.label
                      - component: f7-col
                        config:
                          style:
                            text-align: right
                        slots:
                          default:
                            - component: Label
                              config:
                                text: =loop.item.state
                                style:
                                  background-color: >
                                    =Number.parseFloat(loop.item.state) <
                                    Number(props.valueOne) ? props.colorOne :
                                     Number.parseFloat(loop.item.state) < Number(props.valueTwo) ? props.colorTwo :
                                     Number.parseFloat(loop.item.state) < Number(props.valueThree) ? props.colorThree : props.colorFour
                                  padding: 1px