Retrieving value of a group member with specific tags in a widget

In my widget, I would like to retrieve the string value (state) of an item that meets the following criteria:

It has the tags [“Status”, “OnlineStatus”]
It is a member of a specific group
How can I achieve this using widget expressions?

.items structure:

groupONE
    groupONE_ONE (groupONE)
        ...
        ...
    groupONE_TWO (groupONE)
        myStatusItem (groupONE_TWO) ["Status", "OnlineStatus"]

widget structure:

props:
  parameters:
    - context: item
      type: TEXT
      default: groupONE
      name: groupItem
      required: false

You cannot achieve this using only a single widget expression.

This is one of the exact use cases for an oh-repeater:

Using the itemsInGroup source type you can retrieve all the members of your groupONE_TWO group. Then you use the filter property of the repeater to filter that list down to the one you want (it’s just fine to end up with a repeater list of only one element). The only tricky part of this is the filter expression. Each returned repeater item has a tags array so you just have to check that array for the two tags of interest.

Once you have the repeater properly configured, then in any subsequent widget expressions, you can get the state of the item in any of the usual ways.

Here’s an example to get the actual switch item for my office light switch which is a member of the Switch_OfficeFanLight group and has tags Switch and Light:

- component: oh-repeater
  config:
    for: myItem
    sourceType: itemsInGroup
    groupItem: Switch_OfficeFanLight
    filter: loop.myItem.tags.includes('Switch') && loop.myItem.tags.includes('Light')
  slots:
    default:
      - component: Label
        config:
          text: =@loop.myItem.name

I had hoped to find a solution without using oh_repeater. I fiddled with filterCriteria in vain.
I will use the oh_repeater for now and hope that a variable number of subgroups won’t be an issue.

A problem I encountered in another widget using oh_repeater is that I cannot access the group item “groupONE” to retrieve the “myStatusItem” because it is nested within the intermediate group “groupONE_ONE”.
Actually, I want to access different items that are located in various subgroups.

My main goal is to declare their tags once in the widget code and then simply insert the maingroup of each device (groupONE) in the “Set Props” section. Previously, I did this by specifying the repeating suffixes (“_Switch” for item groupONE_Switch), which worked well, but it assumes that the item names follow a specific structure.

Is there a way to access all items in the different subgroups without using cascaded oh_repeaters?

No. The api returns the data in a json string with the item hierachy intact. So the created array for the repeater is only all of the top level items in the returned string. All the other items are embedded in the members array in each of the groups.

However, the first repeater does, as I said above, actually return the information so you don’t need to make a second api call with a second repeater, the second repeater can simply use that members array from the first one.

Without knowing all the specifics here, however, this does sound a little like a situation where I would simply apply a custom tag to the required items. Doing that once is surely less time consuming than developing a complex widget to get the items via groups.

I found a way to retrieve all items within a group and its subgroups (across all levels) with just one API call.

uid: wid_ItemByGroupAndTags
tags: []
props:
  parameters:
    - context: item
      default: Test_Group
      description: Group item, containing all desired items
      name: groupItem
      required: false
      type: TEXT
    - description: Filter-Tag (Switch, Light, Control, Hue)
      default: Hue
      label: Use
      name: myTag
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Feb 22, 2025, 5:29:53 PM
component: oh-context
config:
  functions:
    flattenRecursive: "=(grpArr) => ((recFunc, a) => [a].reduce((acc, x) => acc.concat(x.members ? recFunc(recFunc, x.members) : [x]), []))((recFunc, a) => a.reduce((acc, x) => acc.concat(x.members ? recFunc(recFunc, x.members) : [x]), []), grpArr)"
slots:
  default:
    - component: f7-card
      config:
        title: The first repeater traverses the group structure downward; the context provides an accessible variable that contains all items (including subgroups).
      slots:
        default:
          - component: oh-repeater
            config:
              for: repTop
              sourceType: itemsInGroup
              groupItem: =props.groupItem
            slots:
              default:
                - component: oh-context
                  config:
                    #Ensure that the flattened array is accessible from this layer downward.
                    variables:
                      arrTopFlat: =fn.flattenRecursive(loop.repTop)
                  slots:
                    default:
                      - component: oh-repeater
                        config:
                          #This repeater iterates over all items in the flattened item array.
                          for: repItems
                          sourceType: array
                          in: =vars.arrTopFlat
                          filter: loop.repItems.tags.includes(props.myTag)
                        slots:
                          default:
                            - component: Label
                              config:
                                text: =loop.repItems.tags
                                style:
                                  background: lightblue

The function is a bit tricky because, in widgets, a function cannot call itself recursively; therefore, you need to implement the recursion within the function. I tried to present it more clearly by naming the variables in the function more explicitly.

This code block is placed above all other widget components, and whenever I need a specific item (by tag) from within the mentioned group - for a button, slider, etc. - I can grab it (or multiple items) without making a new call by using the array variable (arrTopFlat).

It would be great if widgets natively provide the ability to filter by both groups and tags within the oh-repeater.

1 Like