Is there is better way how to combine things to one thing?

Is there a way how to combine output of two things into one to display?

I’m doing it in rules, manipulating label or state

rule "xx"
when
    
then
    something.setLabel("Cleaned " + diff.toString + "d ago | " + last.toString("dd.MM") + " (" + count + ")")
end

same principle can be applied to state as well, but … it would be nice to have something similar in items file like

String something1 "something [%s]"
String something2 "something [%s]"

String combined "combined output [%something1 + " | " + %something2]"

But i guess it is not possible right?

basically from this:

Number      Water_Temp_Max          "Highest [%.1f °C]"             <temperature>   (gWeather)
Number      Water_Temp_Min          "Lowest [%.1f °C]"              <temperature>   (gWeather)

achieve something like this without rules

Screenshot_1

Not possible.
What do you think is wrong with using rules?

Not being funny, there are often posts wishing some feature or another to be implemented outside of rules. They generally involve just as much typing etc. and offer less flexibility, so the attraction puzzles me.

2 Likes

there is nothing wrong with rules, but formatting is done on definition level, so by working with rules I’m loosing formatting, eg. I need to care to format output in rules and thus having it on two places which is not really nice when you have more then enough things to work with

let’s see this example

/* humidity min/max */
rule "Set daily max and min humidity"
when
    Item Weather_Humidity changed or
    Time cron "0 2 0 * * ?" or
    System started
then
    val max = Weather_Humidity.maximumSince(now.withTimeAtStartOfDay)
    val min = Weather_Humidity.minimumSince(now.withTimeAtStartOfDay)
    if (max !== null && min !== null) {
        postUpdate(Weather_Hum_Max, max.state)
        postUpdate(Weather_Hum_Min, min.state)
        
        val result = min.state.toString + " % - " + max.state.toString + " %"
        postUpdate(Weather_Hum_MinMax, result)        
    }
end

this is doing what I’m mentioning, but formatting originally is done in items file for numbers eg. I do have 0 decimals in each Item, but I can’t format String in same way, so I need to tweak that rule to have it in there, as well as “%” or “°C” or whatever, which is not really flexible

Number      Weather_Hum_Max         "Highest Humidity [%.0f %%]"    <humidity>      (gWeather)
Number      Weather_Hum_Min         "Lowest Humidity [%.0f %%]"     <humidity>      (gWeather)
String      Weather_Hum_MinMax      "Min/Max [%s]"                  <humidity>

and without formatting, it for some reason looks like this currently (eventho 25% is stored inside original Min item correctly as 25% not 25.0%)

Screenshot_1

simply said: rules are fine, but adds more complexity on formatting… which is not necessary --> merging already formated outputs from singleItems would be quite handy in many places

An alternative view is that by working with rules you have full and flexible control of formatting. One man’s chore is another’s opportunity. Another user would want individual Items expressed like 21.75% but 22% in a combined summary.

For your particular task, what you would find useful is an imaginary myItem.toStringUsingDefaultFormat I guess :wink:
String::format should be a useful tool for you here, but I don’t think there’s an easy way in rules to access the default [format] defined into an Item?

Couldn’t the rule just output the desired format to the String? Formatting in an Item is optional.

Maybe you can declare your Items as UoM-Items ? Let’s say your Item(s) looks like this:

Number:Temperature Warmwasser_test          "Aktueller Zählerstand [%.1f °C]"             (gWarmwasser)

and your rule makes something like this:

rule "test Concat"
  when
    Item Dummy1 changed to ON
  then
   var String Format_String = " leer"
   Format_String = Warmwasser_test.state.toString + " / " + Warmwasser_test.state.toString
   logInfo("Concat", "new String {}", Format_String)
 end

The Result in the Logger looks like:

new String 22.0 °C / 22.0 °C

… Voila, no more suffixes to concat in the rule.

But no control over decimal places, without further work.

@kriznik point is that he doesn’t want to use a rule, not there is any difficulty building one.

that produced this

2020-04-03 14:36:22.338 [INFO ] [clipse.smarthome.model.script.Concat] - new String 25.0 / 72.0

so no idea how you made it with suffix, as my given items have formatting in things file defined as yours.

anyway this is exactly why I hate rules (because I’m java dumb) :smiley:

    val max = Weather_Humidity.maximumSince(now.withTimeAtStartOfDay)
    val min = Weather_Humidity.minimumSince(now.withTimeAtStartOfDay)
    if (max !== null && min !== null) {
        postUpdate(Weather_Hum_Max, max.state)
        postUpdate(Weather_Hum_Min, min.state)

        var result = String::format("%.0f %% | %.0f %%", min.state, max.state)
        logInfo("test", result)
        postUpdate(Weather_Hum_MinMax, result) 

==>

2020-04-03 14:33:46.471 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Error during the execution of startup rule 'Set daily max and min humidity': f != org.eclipse.smarthome.core.library.types.DecimalType

I’ve tried to declare it as Number, withou luck as well… what’s wrong here?

What sort of thing is max here? (I think it’s a Number)

Would that sort of thing have a .state method? It’s generally Items that have that.
Try to draw a very clear distinction between Items, those magical system objects, and ordinary variables in rule.

as rossko said min and max are “simple” variables. They have no “state”.Object, and I have to say that I’m a dump too (not only in java :wink:)

Can you post the Definitions of your Items “Weather_Hum_Max” and “Weather_Hum_Min”

Number      Weather_Hum_Max         "Highest Humidity [%.0f %%]"    <humidity>      (gWeather)
Number      Weather_Hum_Min         "Lowest Humidity [%.0f %%]"     <humidity>      (gWeather)
String      Weather_Hum_MinMax      "Min/Max [%s]"                  <humidity>

its number and without state it’s not working for postupdate tho … and without state in that given String:format it’s not working either :slight_smile:

var result = String::format("%.0f %% | %.0f %%", min, max)
Error during the execution of startup rule 'Set daily max and min humidity': f != org.openhab.core.persistence.internal.QueryablePersistenceServiceDelegate$1

When you’re having trouble, at least do one thing at a time to simplify your problem. It’s a bit ambitious for someone “java dumb” to try multi-argument formatting.
When you are having trouble with variables, log them out and see what is going on.
These are basic fault-finding procedures.

am not that much java dumb, what I hate about it mainly is that it is not easily able to work with different datatypes and constantly complaining about something can’t cast to something else.

In this case, it does not matter if it is multi or not, both items are exactly the same.

and sure, this works

        var mi = 23.53
        var mx = 267.241

        var result = String::format("%.0f %% | %.0f %%", mi, mx)

so issue really is how to work with persisted number min/maxsince as number correctly so Java stop shiting itself while formating it

because this

val min = Weather_Humidity.minimumSince(now.withTimeAtStartOfDay) as Number

is not the way … :slight_smile:

Error during the execution of startup rule 'Set daily max and min humidity': Could not cast org.openhab.core.persistence.internal.QueryablePersistenceServiceDelegate$1@1c2d678b to java.lang.Number

and because this is … not complicated at all :slight_smile:
this bit solves it

val min = Weather_Humidity.minimumSince(now.withTimeAtStartOfDay)
    if (max !== null && min !== null) {
        postUpdate(Weather_Hum_Max, max.state)
        postUpdate(Weather_Hum_Min, min.state)

        val mi = (min.state as Number).floatValue
        val result = String::format("%.0f %% | %.0f %%", mi, mi)

I mean … bit of overengeneered :smiley:

I’d do it like this:

    var min = (Weather_Humidity.minimumSince(now.withTimeAtStartOfDay).state as Number).floatValue
    var max = (Weather_Humidity.maximumSince(now.withTimeAtStartOfDay).state as Number).floatValue
if (max !== null && min !== null) {
        Weather_Hum_Max.postUpdate(max)
        Weather_Hum_Min.postUpdate(min)
        var result = String::format("%.0f %% | %.0f %%", min, max)
}

Okay, as you can’t be arsed I have experimented for you. It doesn’t have much to do with orginal query.

test rule

var max = nm_Out_temp.maximumSince(now.withTimeAtStartOfDay, "rrd4j")
logInfo("test", " max returns {}", max)
logInfo("test", " max value {}", max.state)
logInfo("test", " max stamp {}", max.timestamp)
var av = nm_Out_temp.averageSince(now.withTimeAtStartOfDay, "rrd4j")
logInfo("test", " av returns {}", av)

results

2020-04-03 15:05:48.130 [INFO ] [.eclipse.smarthome.model.script.test] -  max returns org.openhab.core.persistence.internal.QueryablePersistenceServiceDelegate$1@1ad2ff0
2020-04-03 15:05:48.131 [INFO ] [.eclipse.smarthome.model.script.test] -  max value 11.520000000000001
2020-04-03 15:05:48.132 [INFO ] [.eclipse.smarthome.model.script.test] -  max stamp Fri Apr 03 14:52:00 BST 2020
2020-04-03 15:05:48.139 [INFO ] [.eclipse.smarthome.model.script.test] -  av returns 8.998655110502590

It seems that maximumSince() returns a HistoricItem type object, which includes the timestamp of the max, so I suppose that makes sense.
In contrast, averageSince() returns a plain number, with no time component.

A revelation!! I’m going to clarify the docs on returned object. I’ve only used average and expected max/min o behave the same.

In your case,

val max = Weather_Humidity.maximumSince(now.withTimeAtStartOfDay).state as Number

should do the trick.

The next challenge is getting the java print formatter to play nice with an openHAB Number type. The “f” formatter won’t play, and insists on a decimal (like it says in the error message)

var max = nm_Out_temp.maximumSince(now.withTimeAtStartOfDay, "rrd4j").state as Number
logInfo("test", " max value {}", max)
var xx = String::format("%.0f %%", max.floatValue)
logInfo("test", " xx string {}", xx)
2020-04-03 15:20:44.706 [INFO ] [.eclipse.smarthome.model.script.test] -  max value 12.09
2020-04-03 15:20:44.736 [INFO ] [.eclipse.smarthome.model.script.test] -  xx string 12 %
1 Like

that’s very neat way of what I have already figured out, thanks :wink:

thank you, at least it was for something good at the end :slight_smile:

this is quite neat and working code at the end

    val max = (Weather_Humidity.maximumSince(now.withTimeAtStartOfDay).state as Number).floatValue
    val min = (Weather_Humidity.minimumSince(now.withTimeAtStartOfDay).state as Number).floatValue
    if (max != null && min != null) {
        postUpdate(Weather_Hum_Max, max)
        postUpdate(Weather_Hum_Min, min)
        postUpdate(Weather_Hum_MinMax, String::format("%.0f%% - %.0f%%", min, max))
    }