[SOLVED] Change group icon via rule

Hi there,

i need a rule to update an group icon when on of the group items is changing to 1 or below 2.0.

I got some Homematic Contacts and heating units.
The contacts only show LOWBAT where 0 = full and 1 = empty.
The heating units are able to show an value in Volts like 2.80.
And all my items are in the same group to open them in my sitemap.

Items:

Contact itmTuer_Flur_BAT "Batterie Tür Flur [MAP(LOWBAT.map):%s]" <battery > (Flur, BATTERY) {homematic="address=XXX, channel=1, parameter=LOWBAT"}

Contact itmFenster_Schlafzimmer_BAT "Batterie Fenster Schlafzimmer [MAP(LOWBAT.map):%s]" <battery> (Schlafzimmer, BATTERY) {homematic="address=XXX, channel=1, parameter=LOWBAT"}
Contact itmFenster_Badezimmer_BAT "Batterie Fenster Badezimmer [MAP(LOWBAT.map):%s]" <battery> (Badezimmer, BATTERY) {homematic="address=XXX, channel=1, parameter=LOWBAT"}
Contact itmFenster_Kueche_BAT "Batterie Fenster Küche [MAP(LOWBAT.map):%s]" <battery> (Kueche, BATTERY) {homematic="address=XXX, channel=1, parameter=LOWBAT"}

Number itmHeizung_Schlafzimmer_BAT "Batterie Heizung Schlafzimmer [%.2f V]" <battery> (Schlafzimmer, BATTERY) {homematic="address=XXX, channel=4, parameter=BATTERY_STATE"}
Number itmHeizung_Badezimmer_BAT "Batterie Heizung Badezimmer [%.2f V]" <battery> (Badezimmer, BATTERY) {homematic="address=XXX, channel=4, parameter=BATTERY_STATE"}
Number itmHeizung_Kueche_BAT "Batterie Heizung Küche [%.2f V]" <battery> (Kueche, BATTERY) {homematic="address=XXX, channel=4, parameter=BATTERY_STATE"}

Sitemap:

    Frame label="Batteriezustand"
        {
            Group item=BATTERY label="Alle Batterien" icon="battery"
        }

I found a rule in the google groups for openhab:
https://groups.google.com/forum/m/#!category-topic/openhab/sitemaps/NdYUMO5S7jI

rule SetLevel
when
 Item House changed or
 Item Flood changed
then
 var level = (Flood.state == ON) ? "high" : "low"
 Level.postUpdate(level)
end

I´m not sure about this so i need someone to have look at it.

  1. Do i need all the imports ?
  2. Could the chain of ORs work probaly ?
  3. What about the (Flood.state == ON) part, i´m not sure how to change this example for my needs.
import org.openhab.core.library.types.*
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*
import org.openhab.core.library.types.DecimalType

rule "Change Battery Group Icon"

    when
        Item itmTuer_Flur_BAT == 1 or
        Item itmFenster_Schlafzimmer_BAT == 1 or
        Item itmFenster_Badezimmer_BAT == 1 or
        Item itmFenster_Kueche_BAT == 1 or
        Item itmHeizung_Schlafzimmer_BAT <= 2.00 or
        Item itmHeizung_Badezimmer_BAT <= 2.00 or
        Item itmHeizung_Kueche_BAT <= 2.00

    then
        var level = (Flood.state == ON) ? "high" : "low"
        BATTERY.postUpdate(level)

end

Cheers
Michael

The when clause is what triggers the rule. because you have two different types of items, it’s a bit tricky. My suggestion is to build two groups for your battery items and a proxy Item:

Group:Switch:OR(ON, OFF) MyLowBatt
Group:Number:MIN MyBattLevel
Switch LowBattAll "Battery level [MAP(level.map):%s]"

plus a simple rule:

rule "update LowBattAll"
when
    Item MyLowBatt received update or
    Item MyBattLevel received update
then
    if (MyLowBatt.state == ON || (MyBattLevel.state as decimalType <=2))
        LowBattAll.postUpdate(ON)
    else
        LowBattAll.postUpdate(OFF)
end

and a mapping level.map:

OFF=normal
ON=low
-=unintialized
1 Like

tl;dr

  • You can’t mix Contacts and Numbers in the same group and have a meaningful summary state for the group
  • The icon for an Item or a Group is based on its state, you must have a separate icon_state.png file for every possible state so having a different Icon for an Item (or Group) that can be a floating point number is impossible
  • Rule triggers are based on events, not states
  • To achieve what you want you need to have a separate Item (not Group) to represent BATTERY that has two or three different possible states, create an icon for each potential state, and a rule that calculates BATTERY’s state based on the state of your Contacts and Number Items. You can use a Frame with the BATTERY Item to make it behave on the sitemap like the Group, but you will have to list each Item individually on your sitemap instead of using the Group.

First of all, review the sitemap wiki page for how dynamic icons work. In short the icon that gets displayed is based on the state of the Group Item.

I notice that you do not have a Group Item named BATTERY in your list of Items defined. You must define the Group and in your case you need to set the way it rolls up and summarizes the values of all its members (see the Group section on the Items wiki page).

But one problem I see already is you have a mix of Item types that are a member of BATTERY. That likely won’t work as expected because openHAB needs all the members of the Group to be of a consistent type in order to roll it up. For example, you have a mixture of Contact and Number Items, so what sort of Item should the Group behave as, a Contact or a Number? I don’t think it can be both.

Finally, you have two conditions under which you want the state to change and they are somewhat incompatible as stated. You can have one Icon for when the Group’s state is 1 and another for when it is 2.80, (see the Items wiki page for how icons work). The first problem with this is there really isn’t a good way to summarize the Item’s states in such a way that the Group’s state will tell you this information. MAX, MIN, AND, OR, and AVG are your options.

In looking at your rule I see more problems/misconceptions.

The when clause is based on events, not states. This is why it makes no sense to have an AND in a when clause, because no two events will take place at the same time. This is also why it makes no sense to have a < or > in a when clause. The rule can trigger when an Item changes, receives a commands, or even when an Item changes to a certain value but that is it. This when clause is based on state, not events so all this logic needs to move into the rule itself.

Another problem is that when you send a command or post an update to a Group it passes that value on to all of the members of the Group. So if you send a postUpdate(“high”) to BATTERY you will get all sorts of errors because “high” is an invalid state for both Numbers and Contacts. Ans since the Group’s state is based on the states of its members it is not independently commandable or updateable.

Unfortunately you can’t get there from here using a Groups. To get the behavior you are after you will have to abandon the Group on your sitemap entirely and instead duplicate the behavior using a Frame. But this means you will have to list each Item individually on the sitemap.

Instead you can put the Number Items and Contact Items into separate Groups and create a String Item to represent the “high”, “low” state.

#Items

String BATTERY "Current Battery Levels are [%s]" <battery>

Group gBatteryContacts:AND(CLOSED, OPEN) // will be OPEN if one or more Contacts are OPEN
Group gBatteryVolts:MIN // will be the minimum of all the Numbers

Contact itmTuer_Flur_BAT "Batterie Tür Flur [MAP(LOWBAT.map):%s]" <battery > (Flur, gBatteryContacts) {homematic="address=XXX, channel=1, parameter=LOWBAT"}

Contact itmFenster_Schlafzimmer_BAT "Batterie Fenster Schlafzimmer [MAP(LOWBAT.map):%s]" <battery> (Schlafzimmer, gBatteryContacts) {homematic="address=XXX, channel=1, parameter=LOWBAT"}
Contact itmFenster_Badezimmer_BAT "Batterie Fenster Badezimmer [MAP(LOWBAT.map):%s]" <battery> (Badezimmer, gBatteryContacts) {homematic="address=XXX, channel=1, parameter=LOWBAT"}
Contact itmFenster_Kueche_BAT "Batterie Fenster Küche [MAP(LOWBAT.map):%s]" <battery> (Kueche, gBatteryContacts) {homematic="address=XXX, channel=1, parameter=LOWBAT"}

Number itmHeizung_Schlafzimmer_BAT "Batterie Heizung Schlafzimmer [%.2f V]" <battery> (Schlafzimmer, gBatteryVolts) {homematic="address=XXX, channel=4, parameter=BATTERY_STATE"}
Number itmHeizung_Badezimmer_BAT "Batterie Heizung Badezimmer [%.2f V]" <battery> (Badezimmer, gBatteryVolts) {homematic="address=XXX, channel=4, parameter=BATTERY_STATE"}
Number itmHeizung_Kueche_BAT "Batterie Heizung Küche [%.2f V]" <battery> (Kueche, gBatteryVolts) {homematic="address=XXX, channel=4, parameter=BATTERY_STATE"}

#Rule
The rule will trigger on any updates to either Group and calculate the value for BATTERY

import org.openhab.core.library.types.*

rule "Calculate Battery Level"
when
    Item gBatteryContacts received update or
    Item gBatteryVolts received update
then
    // Since gBatteryContacts will be OPEN if any one of the members are 1 we only need check its state
    // Similarly gBatteryVolts will be the minimum value of all of its members so we only need check its state
    if(gBatteryContacts.state == OPEN || (gBatteryVolts.state as DecimalType) <= 2.0) {
        BATTERY.sendCommand("low")
    }
    else {
        BATTERY.sendCommand("high")
    }
end

NOTE: I use the long form if statement so you can add logging statements more easily if the logic isn’t quite right

#Sitemap
You can’t use the Groups on your sitemap. Groups on the sitemap only allow you to have default behavior, no customization or special cases are allowed. But you can get the same subframe behavior of a Group.

Test item=BATTERY {
    Text item=itmTuer_Flur_BAT 
    Text item=itmFenster_Schlafzimmer_BAT 
...
}

#Icons
Finally, you must have two icons in the webaps/images folder. One named “battery_high.png” and the other “battery_low.png”.

1 Like

Hi Rich,

i´ve read your post and understand it.
It helps me alot to understand how OpenHAB works to get deeper into rules and building up this whole system.

Items:

String Battery"Batteriezustand: [%s]" <battery>
Group Battery_low:AND(CLOSED, OPEN)

// Designer says: missing EOF at ‘:’

Group Battery_volts:MIN

... homematic components

Rule:

import org.openhab.core.library.types.*

rule "Change Battery Icon"

when
    Item Battery_low received update or
    Item Battery_volts received update
then
// Since Battery_low will be OPEN if any one of the members are 1 we only need check its state
// Similarly BATTERY_STATE will be the minimum value of all of its members so we only need check its state
    
    if(Battery_low.state == OPEN || (Battery_volts.state as DecimalType) <= 2.0)

// Couldn’t resolve reference to JvmIdentifiableElement ‘Battery_volts’.
// Couldn’t resolve reference to JvmIdentifiableElement ‘state’.

        {
            Battery.sendCommand("low")
        }
    else
        {
            Battery.sendCommand("high")
        }
end

Sitemap:

    Frame label="Batteriezustand"
        {
            Text item=Battery
            {
                Text item=itmTuer_Flur_BAT
                Text item=itmFenster_Schlafzimmer_BAT
                Text item=itmHeizung_Schlafzimmer_BAT
                Text item=itmFenster_Badezimmer_BAT
                Text item=itmHeizung_Badezimmer_BAT
                Text item=itmFenster_Kueche_BAT
                Text item=itmHeizung_Kueche_BAT
            }
        }

I don´t know if the rule is working but the whole sitemap is broken because of the EOF error at Battery_low.
Only half of the icons are shown, the rest got an missing image symbol becaue they´re pointing at text.png.
When take out the Group Battery_low the same error is shown at the next Group Battery_volts.

Any ideas ?

Cheers
Michael

Item names are CaSe sEnSiTiVe :wink:

This is caused by a syntax error somewhere in the file. A missing closing bracket is a common cause.

You should be editing these files using Designer. It will immediately find and tell you when you have a syntax error like this.

@Udo_Hartmann: Yeah i know, i changed the Names from BATTERY to Battery as i was writing my post.
So my Items are all named right now, but the post got BATTERY and Battery :slight_smile:

@rlkoshak: Look at my Items code, the error is coming from the OpenHAB Designer ! :wink:

And when i comment out the Battery_low Group, the same error will be shown at the Battery_volts Group.
It seems like the Designer and OpenHAB itself doesn´t like the “:”

The sitemap is broken with this two Groups in the default.items …

When i comment out this lines the sitemap isn´t broken.

And there are two errors in the battery.rules
(i put them in my last post as comments starting with //)

Thanks for your help !

Cheers
Michael

OK i found the problem :slight_smile:

String Battery "Batteriezustand [%s]"
Group:Switch:AND(CLOSED, OPEN) Battery_low
Group:Switch:MIN Battery_volts

The sitemap is now correct and the Battery is showing an icon, but it´s the wrong one …
The battery-high.png icon is displayed but all LOWBAT are 0 and now BATTERY_STATE is under 2.00 Volts.

I´m going to take a deeper look tomorrow.

Cheers
Michael

I messed up. You need to tell it what route of item the group should behave
as. So it should be

Group Battery_low:Contact:AND (CLOSED, OPEN)

I found the problem.
The Value of Battery_low will be CLOSED when one of the Batterys is low and not OPEN.
Also the itemtyp and function has to be behind Group and not the Item name.

This is my final (working) setup.
You´re free to use it in your own setups.

Items:

/* Gruppe Batteriezustand */
String Battery
Group:Switch:AND(CLOSED, OPEN) Battery_low
Group:Number:MIN Battery_volts

... Homematic Items

Sitemap item that´s only visible when one battery is low:
(Something like a notification)

Text item=Battery label="Mindestens eine Batterie ist leer" icon="battery" visibility=[Battery == low] labelcolor=[Battery==low="red"]

Sitemap:

    Frame label="Batteriezustand"
        {
            Text item=Battery label="Alle Batterien" icon="battery"
            {
                Text item=itmTuer_Flur_BAT
                Text item=itmFenster_Schlafzimmer_BAT
                Text item=itmHeizung_Schlafzimmer_BAT
                Text item=itmFenster_Badezimmer_BAT
                Text item=itmHeizung_Badezimmer_BAT
                Text item=itmFenster_Kueche_BAT
                Text item=itmHeizung_Kueche_BAT
            }
        }

battery.rules:

import org.openhab.core.library.types.*

rule "Change Battery Icon"

when
    Item Battery_low received update or
    Item Battery_volts received update

then
// Sobald eine Kontakt-Batterie leer ist wird der Zustand von Battery_low auf CLOSED wechseln und die Regel aktivieren
// ODER
// Sobald eine Heizungs-Batterie unter 2.00 Volt fällt wird die Regel aktiviert
    
    if(Battery_low.state == CLOSED || (Battery_volts.state as DecimalType) <= 2.00)
        {
            Battery.sendCommand("low")
            executeCommandLine("sudo yowsup-cli demos -s XXX 'Mindestens eine Batterie ist leer, bitte prüfen!' -c /home/pi/config.yowsup", 5000)
        }
    else
        {
            Battery.sendCommand("high")
        }
end

Cheers
Michael