Rule to count open windows

Hi there,

I would like to count if/how many windows are open at the moment.
This should be the base for a reminder when I leave the house and there is still an open window.

Unfortunately the rule doesn’t count reliable :frowning:
I often get an alarm even when all windows are closed.

// ITEMS
// Fensteroffen    
    Switch  vFensterOffenEG                 "Fenster im EG offen [(%d)]"       <selfkey>               (Gstatus,Gfenster,Goffen)
// RULE
var Number counterFensteregoffen = 0

// Erdgeschoss
rule "Fenster EG offen Counter ++"
    when
        Item eg_bd_k_fenster    changed to OPEN or
        Item eg_wzost_k_fenster changed to OPEN or
        Item eg_az_k_fenster    changed to OPEN or
        Item eg_ku_k_fenster    changed to OPEN or
        Item eg_ku_k_tuer       changed to OPEN
    then
        logInfo("RULE", "--> Fenster EG offen Counter +")
        counterFensteregoffen = counterFensteregoffen + 1
        postUpdate(vFensterOffenEG, ON)
end


rule "Fenster EG offen Counter --"
    when
        Item eg_bd_k_fenster    changed to CLOSED or
        Item eg_wzost_k_fenster changed to CLOSED or
        Item eg_az_k_fenster    changed to CLOSED or
        Item eg_ku_k_fenster    changed to CLOSED or
        Item eg_ku_k_tuer       changed to CLOSED
    then
        logInfo("RULE", "--> Fenster EG offen Counter -")
        counterFensteregoffen = counterFensteregoffen - 1
        if (counterFensteregoffen == 0) {
            logInfo("RULE", "--> Fenster EG offen Counter = 0 & vFensterOffenEG = OFF")
            postUpdate(vFensterOffenEG, OFF)
        }
end

Start with creating a group (named Fenster_EG in this example):

Group:Contact:OR(OPEN,CLOSED) Fenster_EG "Fenster [(%d)]"

and make your windows member of that group. Then try something like:

rule "fenster counter"
when
  Item Fenster_EG received update
then
  val Number counterFensteregoffen = Fenster_EG.members.filter[ NumberItem i | i.state==OPEN ].size

  if ((counterFensteregoffen == 0) && (vFensterOffenEG.state != OFF)) vFensterOffenEG.postUpdate(OFF)
  if ((counterFensteregoffen > 0) && (vFensterOffenEG.state != ON)) vFensterOffenEG.postUpdate(ON)
end

why dont you make

Group:Switch:OR(ON,OFF) Gfenster  "Fenster Offen [ Offen: %d ]"

instead of just a normal group item ?

will look like this:

01

2 Likes

I get the error below:
Type mismatch: cannot convert from (NumberItem)=>boolean to Function1<? super Item, Boolean>

Try to create the group like in my example above, hopefully that helps. If not, please post some more detailed (error) logging and your item configurations

That’s one of the items:

Contact eg_bd_k_fenster "Bad EG Fenster [MAP(de.map):%s]" <contact> (Gmax,Gfenster,Gfenstereg,Gstatus,Gbadeg) {channel="max:shuttercontact:KEQ10xxxx:KEQ11xxxx:contact_state"}

It can have the following states:
CLOSED / OPEN / NULL

In VScode I get this error:
Type mismatch: cannot convert from (NumberItem)=>boolean to Function1<? super Item, Boolean>

I believe that something like Group:SUM will add up the items.
I am on my phone so I have limited access to docs but It is explained in the items docs.

When using Contact Items, the Group has to be of type Contact, too:

Group:Contact:OR(OPEN,CLOSED) MyWindows "open Windows [%d]" <window>
Contact Window1 "Window 1 [%s]" (MyWindows) {...}
Contact Window2 "Window 2 [%s]" (MyWindows) {...}
Contact Window3 "Window 3 [%s]" (MyWindows) {...}
Contact Window4 "Window 4 [%s]" (MyWindows) {...}
Contact Window5 "Window 5 [%s]" (MyWindows) {...}

Now, when using

Text item=MyWindows

in sitemap, you should get always the correct information.

If you explicitly want to count them in a rule…

rule "count openwindows"
when
    Member of MyWindows changed
then
    val Number openWindows = MyWindows.members.filter[w|w.state == OPEN].size
    val Number unknownWindows = MyWindows.members.filter[w|w.state == NULL].size
    val Number closedWindows = MyWindows.members.filter[w|w.state == CLOSED].size
    logInfo("window","state for Windows: open: {} closed: {} unknown: {}",openWindows,closedWindows,unknownWindows)
end
1 Like

Really great :slight_smile:

One more thing … how can I use “openWindows” in another rule?

rule "Pushover Alarm Fenster EG offen NEU"
    when
         Item vAusserHaus changed to ON
    then
        if(openWindows>=1) {
            logInfo("RULE", "--> P2 außer Haus und Fenster EG offen / sende Pushover")
            sendPushoverMessage(pushoverBuilder("ACHTUNG: Fenster im EG sind noch offen").withPriority(1).withSound("tugboat"))
        }
end

You can use the variable again in any other rule in the same rules file.

I think he means he wants to use the calculated value in another rule.

One way is to create a ‘global variable’ by defining it outside of any rules, at the beginning of the file. That will be available to any rule within the same rules file.

You’ll want to define it as a var not a val, as you’ll want to update its value sometimes.

General idea;

var  myGlobal = 0

rule "set it"
when
   Item something changed
then
   myGlobal = some calculation
end

rule "use it"
when
...
   var sometihngelse = myGlobal + 10
...
end

If you need to share it across different rules files, the simplest thing is to use an Item, postUpdate it and read .state

Right - I would like to use it in another rule which is in a different file.

I’ll try your example …
Many thanks to all

If you want to use the value in another rules file, you’ll have to assign the value in a proxy item.

Or just reuse the function.

:wink:

I’tried the two rules below (in one file).

It counts correctly but doesn’t send a message.
According to the log the variable “vAusserHaus” works …

var Number openWindowsEG = 0
var Number unknownWindowsEG = 0
var Number closedWindowsEG = 0


rule "count openwindows"
when
    Member of Gfenstereg changed
then
    openWindowsEG = Gfenstereg.members.filter[w|w.state == OPEN].size
    unknownWindowsEG = Gfenstereg.members.filter[w|w.state == NULL].size
    closedWindowsEG = Gfenstereg.members.filter[w|w.state == CLOSED].size
    logInfo("window","Fenster EG Status: open: {} closed: {} unknown: {}",openWindowsEG,closedWindowsEG,unknownWindowsEG)
end


rule "openwindows Alarm bei Verlassen des Hauses"
    when
        Item vAusserHaus changed to ON
    then        
        if (closedWindowsEG>=1) {
            sendPushoverMessage(pushoverBuilder("ACHTUNG: Fenster im EG sind noch offen").withPriority(1).withSound("tugboat"))
        }
end

Perhaps its the pushover that isn’t working. Add logInfo to debug your rule.

rule "openwindows Alarm bei Verlassen des Hauses"
    when
        Item vAusserHaus changed to ON
    then
       logInfo("testing", "triggered with " + closedWindowsEG.toString)
        if (closedWindowsEG>=1) {
            logInfo("testing", "entered IF")
            sendPushoverMessage(pushoverBuilder("ACHTUNG: Fenster im EG sind noch offen").withPriority(1).withSound("tugboat"))
            logInfo("testing", "tried pushover")
        }
end

Hi, I’m running a similar setup with a slightly different approach which I want to share:

items file:

Group:Contact:OR(OPEN,CLOSED) WS "Window Sensors [%s]"

rules file:

...
	if (WS.state == OPEN) {
		var String open_windows = "| "
		WS.members.forEach [ window |
			if (window.state == OPEN) {
				open_windows = open_windows + window.name + " | "
				logInfo("Fenster offen", "Fenster offen" + open_windows )
			}
		]
		sendMail("email@addre.ss", "Es ist noch ein Fenster offen! (" + open_windows + ")", "Es ist noch ein Fenster offen: " + open_windows )
	}
...

So if there’s an open window it will result in an email containing:

Es ist noch ein Fenster offen: | Contact_Heizung | Contact_Schlafzimmer_West | Contact_Schlafzimmer_Nord |

So you can see at once which windows are still open.

Regards, Christian