[SOLVED] Using groups to shorten code

I am not good at writing code. I have many items and I write my rules over and over again to accomplish my goal for all items. I started reading about using groups but have no idea how to implement it with my simple code.

rule "RGB Buttons Mapping for Diner_Light_Left" 
when 
    Item Diner_Light_Left_rgbColor received command
then 
    if (receivedCommand == ON) {
        sendCommand(Diner_Light_Left_Brightness, 100)
    } 
    else if (receivedCommand == OFF) {
        sendCommand(Diner_Light_Left_Brightness, 1)
    } 
    else if (receivedCommand == INCREASE) {
        Diner_Light_Left_Brightness.sendCommand((Diner_Light_Left_Brightness.state as DecimalType) + 1)
    } 
    else if (receivedCommand == DECREASE) {
        Diner_Light_Left_Brightness.sendCommand((Diner_Light_Left_Brightness.state as DecimalType) - 1)
    } 
end



rule "RGB Buttons Mapping for Diner_Light_Center" 
when 
    Item Diner_Light_Center_rgbColor received command
then 
    if (receivedCommand == ON) {
        sendCommand(Diner_Light_Center_Brightness, 100)
    } 
    else if (receivedCommand == OFF) {
        sendCommand(Diner_Light_Center_Brightness, 1)
    } 
    else if (receivedCommand == INCREASE) {
        Diner_Light_Center_Brightness.sendCommand((Diner_Light_Center_Brightness.state as DecimalType) + 1)
    } 
    else if (receivedCommand == DECREASE) {
        Diner_Light_Center_Brightness.sendCommand((Diner_Light_Center_Brightness.state as DecimalType) - 1)
    } 
end

Also another rule I keep using for all items

rule "Diner_Light_Left Slider Switch"
when
    Item Diner_Light_Left_Brightness changed
then
    if (Diner_Light_Left_Brightness.state instanceof DecimalType) {
        if ((Diner_Light_Left_Brightness.state as DecimalType) > 0 && Diner_Light_Left_Power.state != ON) 
            Diner_Light_Left_Power.sendCommand(ON)
        else if ((Diner_Light_Left_Brightness.state as DecimalType) == 0 && Diner_Light_Left_Power.state != OFF) 
            Diner_Light_Left_Power.sendCommand(OFF)
    }
end

rule "Diner_Light_Center Slider Switch"
when
    Item Diner_Light_Center_Brightness changed
then
    if (Diner_Light_Center_Brightness.state instanceof DecimalType) {
        if ((Diner_Light_Center_Brightness.state as DecimalType) > 0 && Diner_Light_Center_Power.state != ON) 
            Diner_Light_Center_Power.sendCommand(ON)
        else if ((Diner_Light_Center_Brightness.state as DecimalType) == 0 && Diner_Light_Center_Power.state != OFF) 
            Diner_Light_Center_Power.sendCommand(OFF)
    }
end

There must be a way to not have a very very long file with code, but instead use groups,
I cannot seem to get my head around it.

maybe someone could shed some light on it

I am not infront of my OH installation atm. Cant test/proof, but it should be along these lines:

groups.items:

.. Diner_Light_Left_Brightness  (gMyGroup) [ ... ]
.. Diner_Light_Center_Brightness (gMyGroup) [ ... ]

groups.rule

rule "Diner Slider Switch"
when
    Member of gMyGroup changed
then
	val triggerItem = triggeringItem
    if (triggerItem.state instanceof DecimalType) {
        if ((triggerItem.state as DecimalType) > 0 && triggerItem.state != ON) 
            triggerItem.sendCommand(ON)
        else if ((triggerItem.state as DecimalType) == 0 && triggerItem.state != OFF) 
            triggerItem.sendCommand(OFF)
    }
end
1 Like

Almost, but OP is using a different Item to send a command to ultimately.

@treks, what you need is to use Ralf’s example but use Design Pattern: Associated Items to get the Item to send the command to based on the name of the Item that triggered the Rule.

Of course, one needs to ask, are all of these Items controlling the same Light? If so do you really need these Rules? When you send an ON command to a Color Item it will turn on that Light. If you send a single number to a Color Item, it will dim the light to that value.

In short, do you even need these Rules?

Anyway, the adjustment to Ralf’s code would be something along the lines of

rule "Any Brightness Item Changed"
when
    Member of Brightnesses changed
then
    if(!triggeringItem.state instanceof DecimalType) return; // don't do anything it undef or uninitialized

    val newState = if(triggeringItem.state > 0) ON else OFF // if brightness is > 0 power needs to be ON

    val powerItem = ScriptServiceUtil.getItemRegistry.getItem(triggeringItem.name.replace("Brightness", "Power"))
    if(powerItem.state != newState) powerItem.sendCommand(newState)
end

Theory of operation: When any member of Brightnesses changes state we first check to see if it is a valid state (i.e. not NULL or UNDEF). If it is an invalid state we just exit the Rule with nothing to do.

Next we determine whether the associated Power Item needs to be ON or OFF. We use a trinary operator which is just a shortcut for:

var newState = OFF
if(triggeringItem.state > 0) {
    newState = ON
}

Finally, we get a reference to the associated Power Item by modifying the name of the triggeringItem. If the calculated newState is different from the current state, we send the newState as a command.

For other techniques to simplify and make Rules more generic see Design Pattern: DRY, How Not to Repeat Yourself in Rules DSL.

1 Like

Dear Rich,

Excellent! Now that I see how it is done!
I had to add fix one exclamation mark typo in the rule and add import org.eclipse.smarthome.model.script.ScriptServiceUtil to the beginning of the file, but it just works and I went from 200+ lines of code to just 12 lines of code.

import org.eclipse.smarthome.model.script.ScriptServiceUtil 
rule "Any Brightness Item Changed"
when
    Member of Brightnesses changed
then
    if(triggeringItem.state instanceof DecimalType) return; // don't do anything it undef or uninitialized

    val newState = if(triggeringItem.state > 0) ON else OFF // if brightness is > 0 power needs to be ON

    val powerItem = ScriptServiceUtil.getItemRegistry.getItem(triggeringItem.name.replace("Brightness", "Power"))
    if(powerItem.state != newState) powerItem.sendCommand(newState)
end

Thank you so much for the help. I will read the design pattern documents again now it makes more sense to me.

I found out that the rule only work when I comment out the following line

if(triggeringItem.state instanceof DecimalType) return; // don't do anything it undef or uninitialized

It might have do with my Yeelight does not like to stay on brightness 0%, maybe I need a proxy item for the dimmer?

No, it’s an error that has been carried over from your original Rule. Dimmer Items carry a PercentType, not a DecimalType.