Another Calculation in dsl rules question - item value minus item value

Hi all,

two ITEMs. pv_… and leistung_ … . Both between 0 an 40 (kWh).

What ist the correct way two calculate with them. This here is not working like it should:

val Number cba_3 = pv_intraday_number.state as Number - leistung_einspeiseheute_number.state as Number

Second question: any form of pv_… * 123.45 (value multiplied with a number) is not working either.

Maybe there is a helpful “how to calc in dsl rules” guide somewhere, to learn it from the scratch.

thx in advance

Hi, try

val cba_3 = (pv_intraday_number.state as Number).floatValue - (leistung_einspeiseheute_number.state as Number).floatValue

Float value is with komma.

.intValue is full number without komma.

I think math should work with both.

Greets

floatValue is not necessary. This should work:

val cba_3 = (pv_intraday_number.state as Number) - (leistung_einspeiseheute_number.state as Number)

If using the *value() methods, use doubleValue() instead of floatValue(). float has a very low precision, double have double the precision of float.

This thread gave me an idea:

Does Textual Rules | openHAB answer the question sufficiently good? What is missing there?

If using the *value() methods, use doubleValue() instead of floatValue(). float has a very low precision, double have double the precision of float.

The empty brackets in DSL Rules can be skipped - .floatValue is the same as .floatValue(). But for power measurements in kWh there is no difference between .doubleValue and .floatValue, unless you are very much worried for precision many places after the decimal comma - like working with Terra Watt Hours in openHAB.

I know, but I dislike it because it’s ambiguous. Even if you’re allowed to do something stupid, you don’t have to.

That’s not entirely true because of how floating points can’t handle certain values. Try to store 0.1, 0.2, 0.3, 0.7 or 0.9 as a float for example. There are lots of values with the same problem. double has the same problem, also being a floating point, but the consequences are much smaller because of increased precision. float has 7 significant digits, double has 15 to 17 significant digits. You also meet the problem if numbers get large fairly quickly with float.

But, “why care”, if the precision you get from float is enough? Because, in today’s 64-bit world, you’re unlikely to save anything by using the 32-bit float over the 64-bit double. CPUs often work in 64-bit with anyway, so the result is that your 32-bit float is made 64-bit by padding instead.

Given all this, the low precision, and the fact that you most likely don’t save anything using it, it’s much better to just use double as a standard, and just forget about float. It won’t hurt when you don’t need the extra precision, but you won’t have to keep considering “the risk” for each use.

If I am not mistaken, doing arithmetic in DSL rules with QuantityType converts to system unit before doing so to make units compatible. This in itself is a reason to use doubleValue for something like kWh (factor 3600000).

How does the above behave, what does it produce? I tried with two items termo1 and r2_temperature on openHAB 5.2 snapshot 5393 both storing degree with Celsius, both of type Number:Temperature.

rule a 
when
  System reached start level 100
then
  logError("B", termo1.state.toString)
  logError("C", r2_temperature.state.toString)
  val diff1 = termo1.getStateAs(Number) - r2_temperature.getStateAs(Number)
  logError("D", diff1.toString)
  logError("class diff1", diff1.class.toString)
  val diff2 = termo1.state as Number - r2_temperature.state as Number
  logError("E", diff2.toString)
  logError("class diff2", diff2.class.toString)
  val Number diff3 = termo1.state as Number - r2_temperature.state as Number
  logError("F", diff3.toString)
  logError("class diff3", diff3.class.toString)
  logError("G", (termo1.state as Number * 5).toString)
  logError("H", (5 * termo1.state as Number).toString)
end

produces

2026-05-31 20:50:36.226 [INFO ] [el.core.internal.ModelRepositoryImpl] - Loading DSL model 'a.rules'
2026-05-31 20:50:37.000 [ERROR] [org.openhab.core.model.script.B     ] - 18.8 °C
2026-05-31 20:50:37.001 [ERROR] [org.openhab.core.model.script.C     ] - 30.7 °C
2026-05-31 20:50:37.004 [ERROR] [org.openhab.core.model.script.D     ] - -11.90
2026-05-31 20:50:37.005 [ERROR] [penhab.core.model.script.class diff1] - class java.math.BigDecimal
2026-05-31 20:50:37.008 [ERROR] [org.openhab.core.model.script.E     ] - -11.90
2026-05-31 20:50:37.010 [ERROR] [penhab.core.model.script.class diff2] - class java.math.BigDecimal
2026-05-31 20:50:37.013 [ERROR] [org.openhab.core.model.script.F     ] - -11.90
2026-05-31 20:50:37.015 [ERROR] [penhab.core.model.script.class diff3] - class java.math.BigDecimal
2026-05-31 20:50:37.017 [ERROR] [org.openhab.core.model.script.G     ] - 1459.75
2026-05-31 20:50:37.020 [ERROR] [org.openhab.core.model.script.H     ] - 1459.75

As long as the state of the item has unit attached to it, the arithmetic should either work or not work, irrespective of the concrete unit, so it does not matter in this test, if it is energy or temperature.

Moreover, to your second question, the G and H line show, that multiplying state with unit to a number does work as expected.

Finally, there is no need to spell the class/type after val because it is only consulted, if otherwise there will be ambiguity or it cannot be deduced - see class diff3 line - same as the other class diff lines.

My items definitions:

Number:Temperature r2_temperature "Temperature" {channel="mqtt:topic:r2:temperature"}
Number:Temperature termo1 "Room temperature [%.1f ℃]" {channel="mqtt:topic:dht22_1:termo", expire="135s,NULL"}

Working with temperatures, you have a very specific case. Try with Farenheit as the unit. And try with one item °C and the other Farenheit. The result will be unexpected. That’s where I consider it a mistake to return BigDecimal as the result of the calculation. It should keep the unit, and the difference is actually expressed in K in the example. You got lucky with both arguments °C input.

I tried mixing Fahrenheit and Celsius degree. termo1.state, and tc.state are in Celsius degree. tE.state is reported as mqtt-channel property being Fahrenheit, but the system has Metric set as Measurement system (config/org/openhab/i18n.config:measurementSystem="SI"), so this Fahrenheit is converted to Celsius. tF.state is temperature in Fahrenheit, it is enforced by the item link:

Thing mqtt:topic:d {
    Type number :termo [stateTopic="a/b/c", transformationPattern="JSONPATH:$.AM2301.Temperature", unit="℃"]
    Type number  : temperatureC "Реле 2"   [stateTopic="m/n/i:0", transformationPattern="JSONPATH:$.temperature.tC", unit="℃"]
    Type number  : temperatureF "Реле 2"   [stateTopic="m/n/i:0", transformationPattern="JSONPATH:$.temperature.tF", unit="°F"]
}
Number:Temperature tC {channel="mqtt:topic:d:temperatureC"}
Number:Temperature tE {channel="mqtt:topic:d:temperatureF"}
Number:Temperature tF {channel="mqtt:topic:d:temperatureF", unit="°F"}
Number:Temperature termo1 [%.1f ℃]" {channel="mqtt:topic:dht22_1:termo", expire="135s,NULL"}

So items tC, tE and tF present the same temperature as feeling.

rule a
when
  System reached start level 100
then
  logError("A", termo1.state.toString)
  logError("B", tC.state.toString)
  logError("C", tE.state.toString)
  logError("D", tF.state.toString)
  logError("E", "value=" + tE.state.toString + " unit " + tE.unit.toString)
  logError("F", "value=" + tF.state.toString + " unit " + tF.unit.toString)
  logError("G", (termo1.getStateAs(Number) - tC.getStateAs(Number)).toString)
  logError("H", (termo1.state as Number - tC.state as Number).toString)
  logError("I", (tC.state as Number - tF.state as Number).toString)
  val diff1 = termo1.state as QuantityType - tC.state
  val diff2 = termo1.state as QuantityType - tE.state
  val diff3 = termo1.state as QuantityType - tF.state
  val diff4 = tC.state as QuantityType - tF.state
  logError("J", diff1.toString       + "|" + diff2.toString       + "|" + diff3.toString       + "|" + diff4.toString)
  logError("K", diff1.unit.toString  + "|" + diff2.unit.toString  + "|" + diff3.unit.toString  + "|" + diff4.unit.toString)
  logError("L", diff1.class.toString + "|" + diff2.class.toString + "|" + diff3.class.toString + "|" + diff4.class.toString)
end

produces

2026-06-01 14:53:57.174 [INFO ] [el.core.internal.ModelRepositoryImpl] - Loading DSL model 'a.rules'
2026-06-01 14:53:57.605 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in DSL model 'a.rules', using it anyway:
QuantityType is a raw type. References to generic type QuantityType<T> should be parameterized
QuantityType is a raw type. References to generic type QuantityType<T> should be parameterized
QuantityType is a raw type. References to generic type QuantityType<T> should be parameterized
QuantityType is a raw type. References to generic type QuantityType<T> should be parameterized
2026-06-01 14:53:58.012 [ERROR] [org.openhab.core.model.script.A     ] - 19.1 °C
2026-06-01 14:53:58.014 [ERROR] [org.openhab.core.model.script.B     ] - 41 °C
2026-06-01 14:53:58.016 [ERROR] [org.openhab.core.model.script.C     ] - 40.94444444444444 °C
2026-06-01 14:53:58.017 [ERROR] [org.openhab.core.model.script.D     ] - 105.699999999999992 °F
2026-06-01 14:53:58.020 [ERROR] [org.openhab.core.model.script.E     ] - value=40.94444444444444 °C unit °C
2026-06-01 14:53:58.023 [ERROR] [org.openhab.core.model.script.F     ] - value=105.699999999999992 °F unit °F
2026-06-01 14:53:58.027 [ERROR] [org.openhab.core.model.script.G     ] - -21.90
2026-06-01 14:53:58.029 [ERROR] [org.openhab.core.model.script.H     ] - -21.90
2026-06-01 14:53:58.032 [ERROR] [org.openhab.core.model.script.I     ] - 0.0555555555555599999999999999999748724444444444448
2026-06-01 14:53:58.042 [ERROR] [org.openhab.core.model.script.J     ] - -21.90 °C|-21.84444444444444 °C|-39.6222222222222177777777777777778 °C|-17.7222222222222177777777777777778 °C
2026-06-01 14:53:58.046 [ERROR] [org.openhab.core.model.script.K     ] - °C|°C|°C|°C
2026-06-01 14:53:58.050 [ERROR] [org.openhab.core.model.script.L     ] - class org.openhab.core.library.types.QuantityType|class org.openhab.core.library.types.QuantityType|class org.openhab.core.library.types.QuantityType|class org.openhab.core.library.types.QuantityType

So on line I substracting the from a temperature in Celsius the same temperature in Fahrenheit, and casting the state to Number produces zero.

The cast for the differences as QuantityType is required, otherwise the minus sign is an error.

For me diff4 is surprizing, because tC is 41 °C, tF is 105.6 °F, 41 °C is the same as 105.6 °F, so I do not understand why their difference is -17°C