There are a couple interesting persistence-related methods one can call on persisted Items, such as minimumSince() and maximumSince(). However, it appears that OpenHAB has no clue about the Units of Measurement when querying persisted data.
For instance, if I persist Wx_OWM_Current_Temperature (member of the gWeatherCurrent group), then I can easily compute the current day’s temperature high and low value as follows:
rule "Daily min/max values for OWM bindings"
when
Time cron "0/15 * * * * ?" or // FOR DEBUG PURPOSES
Item Wx_OWM_Current_Observation_Time changed
then
val String ruleTitle = "Test daily min/max values for OWM bindings"
val DateTime startOfDay = now.withTimeAtStartOfDay
// Weather item:
val GenericItem wi = Wx_OWM_Current_Temperature
val String p = "Wx_OWM_Current_Temperature"
logInfo( ruleTitle, "{}: type of wi.state is '{}'", p, wi.state.class.getCanonicalName() )
// Current value:
val QuantityType<Number> cur = wi.state
// Today's recorded min/max:
val QuantityType<Number> min = wi.minimumSince(startOfDay).state
val QuantityType<Number> max = wi.maximumSince(startOfDay).state
// Now report the class name and item value:
logInfo( ruleTitle, "{}: cur = '{}' is of type '{}'", p, cur, cur.class.getCanonicalName() )
logInfo( ruleTitle, "{}: min = '{}' is of type '{}'", p, min, min.class.getCanonicalName() )
logInfo( ruleTitle, "{}: max = '{}' is of type '{}'", p, max, max.class.getCanonicalName() )
end
This interestingly reveals that wi.minimumSince() and wi.maximumSince() are DecimalType where cur is QuantityType(what I would indeed expect):
2019-03-06 10:01:45.103 [INFO ] [aily min/max values for OWM bindings] - Temperature: type of wi.state is 'org.eclipse.smarthome.core.library.types.QuantityType'
2019-03-06 10:01:45.123 [INFO ] [aily min/max values for OWM bindings] - Temperature: cur = '9.74 °C' is of type 'org.eclipse.smarthome.core.library.types.QuantityType'
2019-03-06 10:01:45.127 [INFO ] [aily min/max values for OWM bindings] - Temperature: min = '8.15' is of type 'org.eclipse.smarthome.core.library.types.DecimalType'
2019-03-06 10:01:45.129 [INFO ] [aily min/max values for OWM bindings] - Temperature: max = '9.74' is of type 'org.eclipse.smarthome.core.library.types.DecimalType'
How can we reassign the UoM from the current item state to the persisted item states? In other words: is there a way to make infer min and max the Units of Measurement from cur?
val DateTime startOfDay = now.withTimeAtStartOfDay
val min = Wx_OWM_Current_Temperature.minimumSince(startOfDay).state
val max = Wx_OWM_Current_Temperature.maximumSince(startOfDay).state
postUpdate(Wx_OWM_Current_Temperature_Min, min)
postUpdate(Wx_OWM_Current_Temperature_Max, max)
logInfo(ruleTitle, "Today's temperature Min - Max values = '{}' - '{}'", min, max)
* Compute daily min and max values for OWM bindings up to 'now'
*/
rule "Daily min/max values for OWM bindings"
when
// Time cron "0/15 * * * * ?" or // DEBUG
// Time cron "0 1 0 * * ?" or // Run at 00:01 daily (reset the daily min/max values)
Item Wx_OWM_Current_Observation_Time changed
then
val String ruleTitle = "Test daily min/max values for OWM bindings"
val DateTime startOfDay = now.withTimeAtStartOfDay
val List<String> weatherParams = newArrayList("Temperature", "Pressure", "Humidity", "Wind_Speed", "Cloudiness")
weatherParams.forEach[ p |
val String s = "Wx_OWM_Current_" + p
// Current Weather item value:
val GenericItem wi = gWeatherCurrent.allMembers.findFirst[ i | i.name == s ]
// Proxy weather items that will hold the daily min/max values up to now:
val GenericItem wi_min = gWeatherCurrent.allMembers.findFirst[ i | i.name == (s + "_Min") ]
val GenericItem wi_max = gWeatherCurrent.allMembers.findFirst[ i | i.name == (s + "_Max") ]
logInfo( ruleTitle, "Fetching Today's '" + p + "' in '"+ s + "' = '" + wi.state + "'" )
// For Wind_Speed, we get values in m/s but want km/h, so multiply the values by 3.6 in that case:
val double factor = if (p == "Wind_Speed") { 3.6 } else { 1.0 }
logInfo( ruleTitle, "{}: factor = {} - type of wi.state is '{}'", p, factor, wi.state.class.getCanonicalName() )
// wi.state is of type QuantityType:
val QuantityType<Number> cur = (wi.state)
// wi.minimumSince(startOfDay).state is of type DecimalType:
val QuantityType<Number> min = (wi.minimumSince(startOfDay).state) // UoM Help Needed!
// wi.maximumSince(startOfDay).state is of type DecimalType:
val QuantityType<Number> max = (wi.maximumSince(startOfDay).state) // UoM Help Needed!
logInfo( ruleTitle, "{}: factor = {} - cur = '{}' is of type '{}' ", p, factor, cur, cur.class.getCanonicalName() )
logInfo( ruleTitle, "{}: factor = {} - min = '{}' is of type '{}' ", p, factor, min, min.class.getCanonicalName() )
logInfo( ruleTitle, "{}: factor = {} - max = '{}' is of type '{}' ", p, factor, max, max.class.getCanonicalName() )
if (p == "Wind_Speed") {
logInfo(ruleTitle, "Wind speed in m/s : {}; {} -- {}", cur, min, max)
/* Sadly the following does not work:
logInfo(ruleTitle, "Wind speed in km/h: {}; {} -- {}",
(cur as QuantityType<Number>).toUnit("km/h"),
(min as QuantityType<Number>).toUnit("km/h"),
(max as QuantityType<Number>).toUnit("km/h")
)
*/
}
// The min/max values lost their UoM. Is there a way to attach the UoM from the parent Item so it propagates to the persisted item?
logInfo(ruleTitle, "Today's '" + p + "' Min - Max values = '" + min + "' - '" + max + "'")
// The following 2 lines won't work as they expect UoM:
postUpdate(wi_min, min)
postUpdate(wi_max, max)
]
end
I was hoping to find somewhere a method like:
val Number min = newNumberFromDecimaltype(
wi.minimumSince(startOfDay).state,
wi.UoM // This obviously / sadly doesn't exist
)
If I try the following, OH bails out with an error on the 2 lines where i add | "°C":
val QuantityType<Temperature> min = Wx_OWM_Current_Temperature.minimumSince(startOfDay).state | "°C"
val QuantityType<Temperature> max = Wx_OWM_Current_Temperature.maximumSince(startOfDay).state | "°C"
So that doesn’t work.
In my example, I’m iterating over 5 weather-related items (Temperature, Wind Speed, Humidity, Cloudiness and Pressure), most of which have different units of measurement.
I tried looking up the UoM from an ArrayList of String items, but that doesn’t work:
val List<String> weatherParamUnits = newArrayList("°C", "hPa", "%", "m/s","%")
int i = 0
weatherParams.forEach[ p |
val String s = "Wx_OWM_Current_" + p
// same code as above
val QuantityType<Number> min = (wi.minimumSince(startOfDay).state) | weatherParamUnits.get(i).toString
val QuantityType<Number> max = (wi.maximumSince(startOfDay).state) | weatherParamUnits.get(i).toString
// (does not work)
I get the following error:
Configuration model 'openweathermap.rules' has errors, therefore ignoring it: [346,76]: no viable alternative at input '|'
[347,76]: no viable alternative at input '|'
val QuantityType<Speed> min = new QuantityType(
Wx_OWM_Current_Wind_Speed.minimumSince(startOfDay).state,
"m/s"
)
then I get the following error message:
Error during the execution of rule 'Daily min/max values for OWM bindings': An error occurred during the script execution: Could not invoke constructor: org.eclipse.smarthome.core.library.types.QuantityType.QuantityType(java.lang.Number,javax.measure.Unit)
If I replace "m/s" with METRES_PER_SECOND then I get:
2019-03-06 15:40:30.112 [ERROR] [ntime.internal.engine.ExecuteRuleJob] - Error during the execution of rule 'Daily min/max values for OWM bindings': The name 'METRES_PER_SECOND' cannot be resolved to an item or type; line 387, column 13, length 17
if (Wx_OWM_Current_Wind_Speed !== null) {
// SIUnits only defines speed as km/h (so 'SIUnits.METRES_PER_SECOND' is not defined)
// However the persisted OWM data is expressed in m/s - hence we multiply the state as Number value by 3.6:
val QuantityType<Speed> min = new QuantityType(
(Wx_OWM_Current_Wind_Speed.minimumSince(startOfDay).state as Number)* 3.6,
SIUnits.KILOMETRE_PER_HOUR // .METRES_PER_SECOND // "m/s"
)
val QuantityType<Speed> max = new QuantityType(
(Wx_OWM_Current_Wind_Speed.maximumSince(startOfDay).state as Number)* 3.6,
SIUnits.KILOMETRE_PER_HOUR // .METRES_PER_SECOND // "m/s"
)
postUpdate(Wx_OWM_Current_Wind_Speed_Min, min)
postUpdate(Wx_OWM_Current_Wind_Speed_Max, max)
logInfo(ruleTitle, "Today's Wind_Speed Min - Max values = '{}' - '{}'", min, max)
}
Now OH2 will complain with the following known error message (see your link):
The field SIUnits.KILOMETRE_PER_HOUR refers to the missing type Object
But the log shows that it works:
2019-03-06 16:14:30.158 [INFO ] [aily min/max values for OWM bindings] - Today's Wind_Speed Min - Max values = '11.16 km/h' - '24.12 km/h'