Using .rules-variable as item label?

Sure will take a little bit of time

Thomas

OK, here is the full example using the tankerkoenig binding. Idea is to get fuel prices and display them in a sorted order or display “closed” if the station is closed.

To achieve that i defined item to hold the actual price, item with the information if station is closed and display items. the rule iterates trough the prices copy them to a map that will be sorted and then transferred to the display items (with korrekt label).

Here are items, rules, transformations and sitemaps.
Items

//------------------------------------------------------------------------------------------------------------------------------------------------------------
//
//    Virtual
//
//------------------------------------------------------------------------------------------------------------------------------------------------------------

    //--------------------------------------------------------------------------------------------------------------------------------------------------------
    //
    //    Fuel stations
    //
    //--------------------------------------------------------------------------------------------------------------------------------------------------------
    Group VT_FuelStation "Tankstellen" <scene_gas_station>

    DateTime VT_FuelStation_LastUpdate "Letztes Update [%1$tH:%1$tM]" <time_clock> (VT_FuelStation)

    Group VT_FuelStation_Source "Tankerkönig Price Items" <scene_gas_station> (VT_FuelStation)
    Number VT_FuelStation_NordoelUetersen_Diesel "Nordoel (Uetersen) [%.3f €]" <scene_gas_station> (VT_FuelStation_Source)
    Number VT_FuelStation_NordoelElmshorn_Diesel "Nordoel (Elmshorn) [%.3f €]" <scene_gas_station> (VT_FuelStation_Source)
    Number VT_FuelStation_HEMElmshorn_Diesel "HEM (Elmshorn) [%.3f €]" <scene_gas_station> (VT_FuelStation_Source)
    Number VT_FuelStation_StarElmshorn_Diesel "Star (Elmshorn) [%.3f €]" <scene_gas_station> (VT_FuelStation_Source)
    Number VT_FuelStation_HEMWedel_Diesel "HEM (Wedel) [%.3f €]" <scene_gas_station> (VT_FuelStation_Source)
    Number VT_FuelStation_SBWedel_Diesel "SB (Wedel) [%.3f €]" <scene_gas_station> (VT_FuelStation_Source)
    
    Group VT_FuelStation_Open "Tankerkönig Open Flag Items" <scene_gas_station> (VT_FuelStation)
    Contact VT_FuelStation_NordoelUetersen_Open "Nordoel (Uetersen) [MAP(contact.map):%s]" <scene_gas_station> (VT_FuelStation_Open)
    Contact VT_FuelStation_NordoelElmshorn_Open "Nordoel (Elmshorn) [MAP(contact.map):%s]" <scene_gas_station> (VT_FuelStation_Open)
    Contact VT_FuelStation_HEMElmshorn_Open "HEM (Elmshorn) [MAP(contact.map):%s]" <scene_gas_station> (VT_FuelStation_Open)
    Contact VT_FuelStation_StarElmshorn_Open "Star (Elmshorn) [MAP(contact.map):%s]" <scene_gas_station> (VT_FuelStation_Open)
    Contact VT_FuelStation_HEMWedel_Open "HEM (Wedel) [MAP(contact.map):%s]" <scene_gas_station> (VT_FuelStation_Open)
    Contact VT_FuelStation_SBWedel_Open "SB (Wedel) [MAP(contact.map):%s]" <scene_gas_station> (VT_FuelStation_Open)

    Group VT_Display_FuelStation "Tankerkönig Display Items" <scene_gas_station> (VT_FuelStation)
    String VT_Display_Fuelstation_1 "Tankstelle 1 [%s]" <scene_gas_station> (VT_Display_FuelStation)
    String VT_Display_Fuelstation_2 "Tankstelle 2 [%s]" <scene_gas_station> (VT_Display_FuelStation)
    String VT_Display_Fuelstation_3 "Tankstelle 3 [%s]" <scene_gas_station> (VT_Display_FuelStation)
    String VT_Display_Fuelstation_4 "Tankstelle 4 [%s]" <scene_gas_station> (VT_Display_FuelStation)
    String VT_Display_Fuelstation_5 "Tankstelle 5 [%s]" <scene_gas_station> (VT_Display_FuelStation)
    String VT_Display_Fuelstation_6 "Tankstelle 6 [%s]" <scene_gas_station> (VT_Display_FuelStation)

Rules

import java.util.ArrayList
import java.util.Map
import java.util.HashMap

//------------------------------------------------------------------------------------------------------------------------------------------------------------
//
// Rule: Retrieve and process fuel station information
//
//------------------------------------------------------------------------------------------------------------------------------------------------------------
rule "Retrieve and process fuel station information"
when

    System started or
    Time cron "0 0/15 * * * ?" or // Every 15 min.
    Item VT_FuelStation_Source received update
    
then

    val Map <String, Double> PriceMap = new HashMap<String, Double>() // Price map = Station name -> gas price
    
    var ArrayList<StringItem> DisplayItems =  new ArrayList<StringItem>()
    var Integer i
    
    
    VT_FuelStation_LastUpdate.postUpdate(new DateTimeType())
    
    // Build map with prices
    VT_FuelStation_Source?.members.forEach[ PriceItem | 
        
        if (PriceItem.state != NULL) {
            
            PriceMap.put(PriceItem.label, (PriceItem.state as DecimalType).doubleValue)
            
        } else {
            
            PriceMap.put(PriceItem.label, 0.0)
            
        }

    ]
    
    // Build array with display items
    DisplayItems.add(0, VT_Display_Fuelstation_1)
    DisplayItems.add(1, VT_Display_Fuelstation_2)
    DisplayItems.add(2, VT_Display_Fuelstation_3)
    DisplayItems.add(3, VT_Display_Fuelstation_4)
    DisplayItems.add(4, VT_Display_Fuelstation_5)
    DisplayItems.add(5, VT_Display_Fuelstation_6)
    
    // Combine prices with display items
    i = 0
    for (PriceEntry : PriceMap.entrySet.sortBy[value]) {
        
        // Set the label of the display items
        DisplayItems.get(i).label = PriceEntry.getKey()
        
        // Set price according to label of display items
        if (PriceEntry.getValue() != 0.0)
        {
            DisplayItems.get(i).postUpdate(String::format("%.3f €", PriceEntry.getValue()))
        } else {
            DisplayItems.get(i).postUpdate("Geschlossen")
        }
        
        // Switch to next display items
        i = i+1
        
    }

end

Sitemap

        Text item=VT_Display_Fuelstation_1 icon="scene_gas_station" {
        Text item=VT_FuelStation_LastUpdate label="Letztes Update [%1$tH:%1$tM]" icon="time_clock"
        Text item=VT_Display_Fuelstation_1 icon="scene_gas_station"
        Text item=VT_Display_Fuelstation_2 icon="scene_gas_station"
        Text item=VT_Display_Fuelstation_3 icon="scene_gas_station"
        Text item=VT_Display_Fuelstation_4 icon="scene_gas_station"
        Text item=VT_Display_Fuelstation_5 icon="scene_gas_station"
        Text item=VT_Display_Fuelstation_6 icon="scene_gas_station"
    }

And thats it. Any optimizations and changes are welcome.

Thomas

Well that is very cool - I will try to translate that to my power use case and post my items, rules and sitemap

im already in trouble - I think you are using a different rule language map is null

Ugh, i forgot to include the imports in the rule. Original post correted.

You should import

import java.util.ArrayList
import java.util.Map
import java.util.HashMap

in the rule

Thomas

Of course sorry I should have worked that out!

One last thing is the sort is ascending - do you know how to make this descending?

Unfortunately no, but if you use it in the same way as i, just start to fill the display item backward.

currently i is going von 0 to 5 if you set i to 5 an decrease it every round it should feel like sorting something descending.

Thomas

1 Like

that works I was investigating TreeMap and a bunch of other stuff but reversing the items in the sitemap works just as well and much easier! thanks for all your help I have a working solution as below:

Heres My working set (note the sitemap items are descending so highest consumption at the top):

Items:

Group:Number:SUM gPower "Overall Power [%.2f KWh]" <energy> 
Number      Kitchen1_Dimmer_Energy "Bench Consumption [%.2f KWh]"  (gPower)	  { channel="zwave:device:Controller:node15:meter_kwh" }
Number      Kitchen2_Dimmer_Energy "Center Consumption [%.2f KWh]"  (gPower)	  { channel="zwave:device:Controller:node12:meter_kwh" }
...
Number      Lounge_3_Dimmer_Energy "3 Consumption [%.2f KWh]"  (gPower)	  { channel="zwave:device:Controller:node17:meter_kwh" }

//power consumption sort order
String Display_gPower_1 "power [%s]" <battery>
String Display_gPower_2 "power [%s]" <battery>
String Display_gPower_3 "power [%s]" <battery>
String Display_gPower_4 "power [%s]" <battery>
String Display_gPower_5 "power [%s]" <battery>
String Display_gPower_6 "power [%s]" <battery>
String Display_gPower_7 "power [%s]" <battery>
String Display_gPower_8 "power [%s]" <battery>
String Display_gPower_9 "power [%s]" <battery>
String Display_gPower_10 "power [%s]" <battery>
String Display_gPower_11 "power [%s]" <battery>
String Display_gPower_12 "power [%s]" <battery>
String Display_gPower_13 "power [%s]" <battery>

Rules


import java.util.ArrayList
import java.util.Map
import java.util.HashMap
//------------------------------------------------------------------------------------------------------------------------------------------------------------
//
// Rule: Retrieve and process power consumption information
//
//------------------------------------------------------------------------------------------------------------------------------------------------------------
rule "Retrieve and process power consumption information"
when
    Time cron "0 0/15 * * * ?" // Every 15 min.
 then
    val Map <String, Double> PowerMap = new HashMap<String, Double>() // power map = power item name -> power value
    var ArrayList<StringItem> DisplayItems =  new ArrayList<StringItem>()
    var Integer i
       
    // Build map with prices
    gPower?.members.forEach[ gPowerItem |       
        if (gPowerItem.state != NULL) {          
            PowerMap.put(gPowerItem.label, (gPowerItem.state as DecimalType).doubleValue)           
        } else {           
            PowerMap.put(gPowerItem.label, 0.0)           
        }
    ]
    
    // Build array with display items
    DisplayItems.add(0, Display_gPower_1)
    DisplayItems.add(1, Display_gPower_2)
    DisplayItems.add(2, Display_gPower_3)
    DisplayItems.add(3, Display_gPower_4)
    DisplayItems.add(4, Display_gPower_5)
    DisplayItems.add(5, Display_gPower_6)
    DisplayItems.add(6, Display_gPower_7)
    DisplayItems.add(7, Display_gPower_8)
    DisplayItems.add(8, Display_gPower_9)
    DisplayItems.add(9, Display_gPower_10)
    DisplayItems.add(10, Display_gPower_11)
    DisplayItems.add(11, Display_gPower_12)
    DisplayItems.add(12, Display_gPower_13)
    
    // Combine values with display items
    i = 0
    for (gPowerEntry : PowerMap.entrySet.sortBy[value]) {
        // Set the label of the display items
        DisplayItems.get(i).label = gPowerEntry.getKey()       
        // Set value according to label of display items
              DisplayItems.get(i).postUpdate(String::format("%.2f kWh", gPowerEntry.getValue()))     
        // Switch to next display items
        i = i+1        
    }

end	

Sitemap

Frame label="Power Consumption" {
			Text item=Display_gPower_13
			Text item=Display_gPower_12
			Text item=Display_gPower_11
			Text item=Display_gPower_10
			Text item=Display_gPower_9
			Text item=Display_gPower_8
			Text item=Display_gPower_7
			Text item=Display_gPower_6
			Text item=Display_gPower_5
			Text item=Display_gPower_4
			Text item=Display_gPower_3
			Text item=Display_gPower_2
			Text item=Display_gPower_1
		}

Hey guys,

could someone confirm that as of openHAB 2.2.0 Build #1075 it is no longer possible to assign a value to a label. Just recognized this morning that i get prices but no more station names.

Thomas

I’m on #1077 and everything just works fine.

Thanks, it is working again.

Thomas

Hi there,

meanwhile i am in the process of reworking my whole systems and i am getting better in using groups. So i decides to use a new approach to simplify my petrol station rules. Here is the result. in my opinion much more smooth.

With the Tankerkönig binding you have to create some station thing that will be linkes to the items. We have three groups of items: Price items, station open information items and display items. We need those to create an ordered display.

Items & Groups

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//  Group: Fuel stations
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Group GRP_Petrolstations "Tankestellen" <scene_gas_station> (GRP_Environment)
    Group GRP_Petrolstation_Display "Tankstellen Anzeige Items" <scene_gas_station> (GRP_Petrolstations)
    Group GRP_Petrolstation_Open "Tankstellen geöffnet Flag Items" <scene_gas_station> (GRP_Petrolstations)
    Group:Number GRP_Petrolstation_Price "Tankerkönig Price Items" <scene_gas_station> (GRP_Petrolstations)

//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//  Thing: Petrolstation
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Group VT_PetrolStation "Tankstellen" <scene_gas_station> (GRP_Virtual)

    DateTime VT_Petrolstation_LastUpdate "Letztes Update [%1$tH:%1$tM]" <time_clock> (VT_Petrolstation)

    Number VT_Petrolstation01_Diesel "Nordoel (Uetersen) [%.3f €]" <scene_gas_station> (VT_Petrolstation, GRP_Petrolstation_Price) // Uetersen Nordoel
    Number VT_Petrolstation02_Diesel "Nordoel (Elmshorn) [%.3f €]" <scene_gas_station> (VT_Petrolstation, GRP_Petrolstation_Price) // Elmshorn Nordoel
    Number VT_Petrolstation03_Diesel "HEM (Elmshorn) [%.3f €]" <scene_gas_station> (VT_Petrolstation, GRP_Petrolstation_Price) // Elmshorn HEM
    Number VT_Petrolstation04_Diesel "Star (Elmshorn) [%.3f €]" <scene_gas_station> (VT_Petrolstation, GRP_Petrolstation_Price) // Elmshorn Star
    Number VT_Petrolstation05_Diesel "HEM (Wedel) [%.3f €]" <scene_gas_station> (VT_Petrolstation, GRP_Petrolstation_Price) // Wedel HEM
    Number VT_Petrolstation06_Diesel "SB (Wedel) [%.3f €]" <scene_gas_station> (VT_Petrolstation, GRP_Petrolstation_Price) // Wedel SB

    Contact VT_Petrolstation01_Open "Nordoel (Uetersen) [MAP(contact.map):%s]" <scene_gas_station> (VT_Petrolstation, GRP_Petrolstation_Open)
    Contact VT_Petrolstation02_Open "Nordoel (Elmshorn) [MAP(contact.map):%s]" <scene_gas_station> (VT_Petrolstation, GRP_Petrolstation_Open)
    Contact VT_Petrolstation03_Open "HEM (Elmshorn) [MAP(contact.map):%s]" <scene_gas_station> (VT_Petrolstation, GRP_Petrolstation_Open)
    Contact VT_Petrolstation04_Open "Star (Elmshorn) [MAP(contact.map):%s]" <scene_gas_station> (VT_Petrolstation, GRP_Petrolstation_Open)
    Contact VT_Petrolstation05_Open "HEM (Wedel) [MAP(contact.map):%s]" <scene_gas_station> (VT_Petrolstation, GRP_Petrolstation_Open)
    Contact VT_Petrolstation06_Open "SB (Wedel) [MAP(contact.map):%s]" <scene_gas_station> (VT_Petrolstation, GRP_Petrolstation_Open)

    String VT_Petrolstation01_Display "Tankstelle 1 [%s]" <scene_gas_station> (VT_Petrolstation, GRP_Petrolstation_Display)
    String VT_Petrolstation02_Display "Tankstelle 2 [%s]" <scene_gas_station> (VT_Petrolstation, GRP_Petrolstation_Display)
    String VT_Petrolstation03_Display "Tankstelle 3 [%s]" <scene_gas_station> (VT_Petrolstation, GRP_Petrolstation_Display)
    String VT_Petrolstation04_Display "Tankstelle 4 [%s]" <scene_gas_station> (VT_Petrolstation, GRP_Petrolstation_Display)
    String VT_Petrolstation05_Display "Tankstelle 5 [%s]" <scene_gas_station> (VT_Petrolstation, GRP_Petrolstation_Display)
    String VT_Petrolstation06_Display "Tankstelle 6 [%s]" <scene_gas_station> (VT_Petrolstation, GRP_Petrolstation_Display)

Rules

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//  Petrolstation rules
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//  Import
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
import java.util.concurrent.locks.ReentrantLock


//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//  Constants and variables
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
var ReentrantLock aLock = new ReentrantLock()


//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// Sort fuel prices and check if station is open
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
rule "Process Petrolstation Information"
when

    Item GRP_Petrolstation_Price received update

then

    aLock.lock()
    try {

        var i = 1 // Additional counter variable

        for (aPrice : GRP_Petrolstation_Price.members.sortBy[state as DecimalType]) { // Another loop to overcome the "Final Variable" vs "Lambda" problem

            val String counter = new String(String::format("%02d", i))
            val String namePrefix = aPrice.name.substring(0, aPrice.name.lastIndexOf('_')-2)
            var StringItem aDisplay = GRP_Petrolstation_Display.members.filter[ f | f.name == namePrefix+counter+"_Display"].head as StringItem
            var ContactItem stationOpen = GRP_Petrolstation_Open.members.filter[ f | f.name == namePrefix+counter+"_Open"].head as ContactItem

            aDisplay.label = aPrice.label
            
            if (stationOpen.state == OPEN) {
                aDisplay.postUpdate(String::format("%.3f €", (aPrice.state as DecimalType).doubleValue()))
            } else {
                aDisplay.postUpdate(transform("MAP", "contact.map", stationOpen.state.toString))
            }

            i = i+1

        }

        VT_Petrolstation_LastUpdate.postUpdate(new DateTimeType())

    } finally { aLock.unlock() }

end

Sitemap

sitemap mymap label="Petrol stations" {

    Frame label="Information" {

        Text item=VT_Petrolstation01_Display icon="scene_gas_station" {
            Text item=VT_Petrolstation_LastUpdate label="Letztes Update [%1$tH:%1$tM]" icon="time_clock"
            Text item=VT_Petrolstation01_Display icon="scene_gas_station"
            Text item=VT_Petrolstation02_Display icon="scene_gas_station"
            Text item=VT_Petrolstation03_Display icon="scene_gas_station"
            Text item=VT_Petrolstation04_Display icon="scene_gas_station"
            Text item=VT_Petrolstation05_Display icon="scene_gas_station"
            Text item=VT_Petrolstation06_Display icon="scene_gas_station"
        }

    }

}

That’s it. As always any comment is welcome.

Thomas

Hi,

I would like to do a similar job renaming labels of each members of a group but I failed.
When i update label of one item, than it works, when I update the state of the items in the group with the same loop it works.WHen I combining it than it not works:

items:

Group g_ForecastTime (g_HomeWeather)
String F03h ( g_ForecastTime )
String F06h ( g_ForecastTime )
String F09h ( g_ForecastTime )
String F12h ( g_ForecastTime )
String F15h ( g_ForecastTime )
String F18h ( g_ForecastTime )
String F21h ( g_ForecastTime )
String F24h ( g_ForecastTime )

Rules:

rule "React on Timestamp of last measurement (localLastMeasurement) change/update 4"
when
    Time cron "0 31 17 1/1 * ? *" //or
then
    g_ForecastTime.members.forEach [ ItemFCTime | ItemFCTime.label = "kutyafüle" ]
end

Error in the log file:

2020-03-21 17:31:01.218 [ERROR] [ntime.internal.engine.ExecuteRuleJob] - Error during the execution of rule 'React on Timestamp of last measurement (localLastMeasurement) change/update 4': Couldn't invoke 'assignValueTo' for feature JvmVoid:  (eProxyURI: weather.rules#|::0.2.2.2.0.0.7.0.1.0.0::0::/2)

Any idea how to fix it?
Thnaks

Just a guess.Typically the system do not know what type your item has.

You could try

(ItemFCTime as StringType).label

or

(ItemFCTime as StringType).setLabel("A new label")
1 Like

Good guess :slight_smile:
works with a small change:

g_ForecastTime.members.forEach [ ItemFCTime | (ItemFCTime as StringItem).setLabel ("kutyafüle") ]

Many thanks for it!