Count State of Items in DateTime Group

Hello all,

I am relatively new to OpenHab and I was really trying to wrap my head around an issue counting Items displaying a time stamp in a DateTime Group. This may be a very simple problem and I apologize in advance if it sounds ridiculous.

The following is an example of an item showing a time stamp when a motion sensor was activated:

DateTime ZONE1_ALARM "Main Entry Door Alarm Time [%1$tH:%1$tM:%1$tS  %1$tm.%1$td.%1$tY]" (gDSCAlarmDoor, gDSCAlarmZones) {channel="dscalarm:zone:MyDSC:zone1:zone_in_alarm" [profile="system:timestamp-update"] , stateDescription=" " [pattern="%1$tH:%1$tM:%1$tS  %1$tm.%1$td.%1$tY"]}

The group contains multiple sensors, and I would like to get a count of the ones displaying the time stamp. The State of the item is either NULL or the time stamp (ex. 09:44:38 08.12.2023)

I have tried

Group:DateTime:COUNT(not NULL) gDSCAlarmDoor

but no success. I would appreciate any thoughts. Thank you much!

Did not test, maybe:

Group:DateTime:COUNT(!NULL) gDSCAlarmDoor

But if this doesn’t work, I guess you will end up with rule, something like this:

rule "count items"
when
    Member of gDSCAlarmDoor changed
then
    val myCount = gDSCAlarmDoor.members.filter[i|i.state!=NULL].size
    gDSCAlarmDoor.postUpdate(myCount)
end

Please be aware that you either have to use a different Item to put the count into, or change the group Item to be an ordinary one (Group without any additional setting other than a Label, Icon and so on)

Hi Udo,

Very much appreciated your suggestions!

The first option did not work and I wonder if it has anything to do with the Group configuration. Maybe COUNT function only works across Number base item.

I used the rule route and created an item to record the count and worked well.

Out of curiosity, would any other aggregation function work on a Group comprised of DateTime items?

Thanks again!

I have something similar, but counting the number of OPEN contact sensors in a group. What I did was using a script transformation in the label / display, and the script counts and returns a string in the format of “#open / #total”. E.g. “2/20”. This is just for my sitemap, e.g.

1 Like

In fact, there are more options, like tihs:

Group:Switch:OR(ON,OFF) gLights "Alle Lichter [(%d)]" <light>

Screenshot 2023-08-14 184915
As you can see, the Group is aggregated as an OR of type Switch. The Group will give the ORed value off all included Items. It will also give the amount off Items which are not OFF.
Please be aware that the one Item not OFF here is a Dimmer Item, it don’t need to be Switch Items only, but the state has to be compatible to ON/OFF.

Thank all for the above suggestions! I was able to get the COUNT by using a rule and a dedicated Number Item to post the number of timestamped, TimeDate Items in my Group.

Number Test_Count  "Number tripped [%d]"

My main intention was to post this number in Label Cell on the Main UI.
Currently, I am able to do so by using the Test_Count.state as the Label.

config:
  label: =items['Test_Count'].displayState || items['Test_Count'].state

I tried to bypass the rule using the following format:

component: oh-label-cell
config:
  label: =items['gDSCZoneTrippedUpdate'].members.filter[i|i.state!=NULL].size

but I get an Error. Would this be a feasible option? Thanks again!

This won’t work. The items object in the widget does not give you access to the complete item but only to an item’s state and (if it is different than the state) the state as formatted by the item’s state description.

You can do what you want, but it requires a little trickery. An oh-repeater will actually return complete items if you are using the itemsInGroup or itemsWithTags source values. In this case, the group version is a perfect fit since that’s the collection of items already.

The important thing to know is that each repeater iteration, in addition to the loop.variableName variable gets two other variables: loop.variableName_idx is the integer index of the loop (starting at 0) and loop.variableName_source which contains the full array that the repeater is iterating through.

So, to get this to work, you set up a repeater to fetch the items in the DateTime group and you put the label cell in the repeater’s default slot. To prevent the repeater from showing one label cell for each of the items in the repeater, use the visible property and the _idx variable:

- component: oh-label-cell
  config:
    visible: =(loop.variableName_idx == 0)

And now you can use the _source variable in the label of the label cell with the array methods as you proposed (though you need the javascript versions)

label: =loop.variableName_source.filter(i => items[i.name].state!='NULL').length

Thank you Justin!
Seems like a definite more elegant solution. I’ll have to digest all the info and report back. Thanks again!

I tried the following, but no success…

uid: test
component: f7-card
config:
  title: test
slots:
  default:
    - component: oh-repeater
      config:
        for: gDSCZoneTrippedUpdate
        sourceType: itemsInGroup
        fetchMetadata: itemsInGroup
      slots:
        default:
          - component: oh-label-cell
            config:
              visible: =(loop.gDSCZoneTrippedUpdate_idx == 0)
              label: =loop.variableName_source.filter(i => items[i.name].state!='NULL').length
Group gDSCZoneTrippedUpdate "Zones Tripped [%d]" 

I apologize for the repeated mistakes…

You forgot to change my generic loop variable variableName into your use case gDSCZoneTrippedUpdate.

Unless you’ve added it yourself, I don’t believe there’s any such thing as itemsInGroup metatdata. Also, if this is all you want to do with the widget, then you don’t need to fetch any metadata at all and can just leave this line out.

You do need, however, to tell the repeater which group item you want to use. In this case, I assume from your earlier posts that the group is gDSCAlarmDoor so you need that as the value of the groupItem variable.

Put it all together and it probably looks something like this:

uid: test
component: f7-card
config:
  title: test
slots:
  default:
    - component: oh-repeater
      config:
        for: gDSCZoneTrippedUpdate
        sourceType: itemsInGroup
        groupItem: gDSCAlarmDoor
      slots:
        default:
          - component: oh-label-cell
            config:
              visible: =(loop.gDSCZoneTrippedUpdate_idx == 0)
              label: =loop.gDSCZoneTrippedUpdate_source.filter(i => items[i.name].state!='NULL').length

Here’s the doc page for the repeater for more specific information:

Hi Justin,
Thank you again for the solution. Initially I was running OH3.3.1. I had then upgraded to OH3.4.4 and worked perfect.
I had a few other areas I need some help with please:

  1. I was trying to modify the font size, color and weight for the oh-block without success. I tried blue as a test:
  • component: oh-block
    config:
    style:
    color: blue
    height: 60px
    and no luck.

I then tried:
blocks:

  • component: oh-block
    config:
    stylesheet: >
    .col > div {
    color: blue
    }
    title: Home Security

Instead of “Home Security” changing color the was the default widget within it that did. Tried a few other things under style like --f7-block-text-color but no luck. This is where I got stuck.

  1. I created a round button, and intended to use the taphold_action. As I depress the button on the Iphone screen, I notice a square shadow that disappears as I release the button. Any thoughts on how the square shadow can be avoided?
                      - component: oh-button
                        config:
                          class:
                            - justify-content-center
                            - display-flex
                            - flex-direction-column
                            - align-item-center
                          icon-f7: xmark_shield_fill
                          iconSize: 40
                          style:
                            --f7-button-bg-color: "#2AD19F"
                            --f7-button-hover-bg-color: "#2AD19F"
                            --f7-button-pressed-bg-color: transparent
                            border-radius: 50%
                            color: white
                            height: 80px
                            margin-left: auto
                            margin-right: auto
                            width: 80px
                          taphold_action: command
                          taphold_actionCommand: "0"
                          taphold_actionItem: PARTITION1_ARM_MODE
                      - component: Label
                        config:
                          class:
                            - align-self-center
                          style:
                            font-size: 12px
                            font-weight: 500
                            margin-top: 0px
                            padding-top: 10px
                          text: DISARM
  1. And lastly, is there a way to add haptic feedback to the oh-button.
    Thank you very much for all the support!

The oh-block is one of the components that doesn’t actually take a style property. You can set the color of the title text by setting the --f7--block-title-text-color but you would either have to do that at some level above the oh-block where you can define a style or with the stylesheet in the oh-block.

Your stylesheet didn’t didn’t work simply because .col > .div not not a correct selector. The title text for the block is in it’s own div element with a class of block-title so you can just use the class name as your selector:

stylesheet: >
  .block-title {
   --f7-block-title-text-color: blue;
  }

I don’t use iOS devices and there are all sort of iOS specific css properties and variables. Sorry, I can’t really help with this one.

Haptic vibration is programmatic, not stylistic. You would have to have access to the underlying javascript for the UI to add that in.

Awsome! Thx again for the prompt response!