Scaling group voltages

I have a rule that scales voltages of TRVs (Thermostatic Radiator Valves) to a % figure which drives the battery icon selected (by OH). The voltages range from 0 to 3.5V max. So my scale up value is 28.571. I can’t help feeling there is a better more efficient way of implementing the rule, particularly if I add a TRV and forget to update the code. I’d prefer if the solution was extensible by using a group or something?

Here is what I have:

rule

rule "Scale_voltages"

when
    Item i_TRV_Lounge_Get_Voltage changed 
    or
    Item i_TRV_Dad_Get_Voltage changed 
    or
    Item i_TRV_Summer_Get_Voltage changed 
then
    if ( i_TRV_Lounge_Get_Voltage.state != NULL && i_TRV_Lounge_Get_Voltage.state != UNDEF && i_TRV_Lounge_Get_Voltage.state  != null) { 
        i_TRV_Lounge_Scaled_Voltage.postUpdate(Float::parseFloat(i_TRV_Lounge_Get_Voltage.state.toString) * 28.571)
    }
    if ( i_TRV_Summer_Get_Voltage.state != NULL && i_TRV_Summer_Get_Voltage.state != UNDEF && i_TRV_Summer_Get_Voltage.state  != null) { 
        i_TRV_Summer_Scaled_Voltage.postUpdate(Float::parseFloat(i_TRV_Summer_Get_Voltage.state.toString) * 28.571 )
    }
    if ( i_TRV_Dad_Get_Voltage.state != NULL && i_TRV_Dad_Get_Voltage.state != UNDEF && i_TRV_Dad_Get_Voltage.state  != null) { 
        i_TRV_Dad_Scaled_Voltage.postUpdate(Float::parseFloat(i_TRV_Dad_Get_Voltage.state.toString) * 28.571 )
    }

end   

items

String i_TRV_Lounge_Get_Voltage     		"Current voltage [%s]V" 	<battery>		(g_HVAC, g_TRV) {channel="mqtt:topic:b_MQTT_Broker:t_TRV_Lounge:c_Voltage"}
String i_TRV_Lounge_Scaled_Voltage			"Voltage"					<battery>		(g_HVAC, g_TRV) 

...etc..
	

Ideas welcome - including critique. :slight_smile:

Scale it at point of delivery, with a transformation.

I think the time has come for you to review the OH Design Patterns.

In this particular case the Design Pattern: Associated Items would probably be most appropriate. Though you would do well to familiarize yourself with what’s there as these will be the tools you use to build good Rules. You may not need them now, but knowing they are there will let you immediately jump to a good solution when you encounter a given need.

So if you put all your TRV’s into a Group, using the above DP, your Rule becomes:

rule "Scale voltages"
when
    Member of TRVs changed
then
    if(triggeringItem.state == NULL || triggeringItem.state == UNDEF) return; // we don't care

    // An Item's state can never be null so there is no need to check for that

    val scaled_name = triggeringItem.name.replace("Get", "Scaled")
    postUpdate(scaled_name, Float::parseFloat(triggeringItem.state.toString) * 28.571)
    
end

To add another TRV, just add the “Get” Item to the TRVs Group and reload the Rule (changes to Group membership don’t always get picked up).

The Python version of the above using Scripted Automation and the Helper Libraries would be:

from core.rules import rule
from core.triggers import when

@rule("Scale voltages")
@when("Member of TRVs changed")
def scale_trv(event):
    if isinstance(event.itemState, UnDefType):
        return

    scaled_name = event.itemName.replace("Get", "Scaled")
    scaled_value = float(str(items[event.itemName])) * 28.571
    events.postUpdate(scaled_name, str(scaled_value))

cheers again Ritch

I am very familiar with DPs as a general term and its application to a number of architectures , but not OH so that link is gratefully received and I shall scour that with interest at bedtimes with my hot choc and Eagles playing on my smart speaker

p.s
The band not the raptors gracing the North American skies :grin:

BTW Ritch, where is the language reference for DSL, it resembles (dreaded) Java … but I hear its not quite the same.

It really doesn’t resemble Java at all. C++ looks more like Java than Rules DSL does. Core Java classes are available in it though, as they are available in all programming languages that run on the Java Runtime Environment, but the syntax bears almost nothing in common with Java beyond what is common among most programming languages.

To quote from the docs,

The rule syntax is based on Xbase and as a result it is sharing many details with Xtend, which is built on top of Xbase as well.

“Sharing many details” doesn’t mean “the same as” though. For example, Xtend supports arrays, classes, functions, and data structures. Rules DSL supports none of those. The definition of a Rule is wholly unique to Rules DSL as is the overall structure of a .rules file. So for reference, the Rules documentation page and Xtend - Classes and Members is as close as we get to a reference. But keep in mind that not everything present will necessarily apply in Rules DSL. And it is not a complete reference. That’s why I wrote Design Pattern: Working with Groups in Rules which covers a lot of the missing filter/map/reduce List operations that are missing from the Xtend docs.

I guess this interaction Ritch, is superceded by our other discussion relating to Jython Scripting so I’ll keep on point and explore that beta testing :grin: