var startTime = heater_Start_Time.state
var endTime = heater_End_Time.state
var totalRuntime = 0
//Calculate Heater Runtime
rule "Calculate Heater Runtime"
when
Item MainHeater changed
then
if(heater_Runtime_Total instanceof QuantityType){
totalRuntime = (heater_Runtime_Total.state as QuantityType).toUnit("s").intValue // get the time in number of seconds
}
if(newState == OFF){
endTime = now
heater_End_Time.postUpdate(endTime)
}
else if(newState == ON){
startTime = now
heater_Start_Time.postUpdate(startTime)
}
else {
return;
}
if(startTime.isBefore(endTime)){
var runtime = java.time.Duration.between(startTime, endTime)
logInfo("Heater", "Heater Duration in Minuten - " + runtime.toMinutes)
totalRuntime = totalRuntime + runtime.toSeconds
heater_Runtime_Total.postUpdate(totalRuntime.toString+" s")
}
end
multiple errors
When I load the file I get this.
Validation issues found in configuration model 'heater_runtime_two.rules', using it anyway:
Cannot reference the field 'heater_Start_Time' before it is defined
Cannot reference the field 'heater_Start_Time' before it is defined
Cannot reference the field 'heater_Start_Time' before it is defined
Cannot reference the field 'heater_End_Time' before it is defined
Cannot reference the field 'heater_End_Time' before it is defined
Cannot reference the field 'heater_End_Time' before it is defined
QuantityType is a raw type. References to generic type QuantityType<T> should be parameterized
when it runs
[ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'heater_runtime_two-1' failed: An error occurred during the script execution: Could not invoke method: org.openhab.core.model.script.actions.BusEvent.postUpdate(org.openhab.core.items.Item,org.openhab.core.types.State) on instance: null in heater_runtime_two
assuming there is a null value in there that needs to be defined first?
also, maybe a stupid question but do all the variables need to be defined as items?
Ah, the penny has just dropped.
You can’t do that assignment as global variables, there is something strange about Item states in that particular context at rules load time.
But it any case, you don’t want to - that would assign the variable as the Item state at the time the rules file loaded. Just at that moment, and never again - a static evaluation.
You’d be wanting to know the states at the time the rule ran, I think?
If you must pre-populate those variables (I can’t see why) you can do so in a ‘System started’ triggered rule.
But there are other difficulties here when you run for the very first time. You need to take account of stuff that has not been initialized.
You can’t get the NULL state of an Item as an integer, for example.
You need to write code that deals with that situation.
If you don’t use these variable anywhere else, don’t have them as globals unnecessarily.
rule "Calculate Heater Runtime"
when
Item MainHeater changed
then
// get the current variable states
// but what if we've never run before?
var startTime = now
if ( !(heater_Start_Time.state instanceof UndefType) ) { // not NULL or UNDEF
startTime = heater_Start_Time.state
}
var endTime = now
if ( !(heater_End_Time.state instanceof UndefType) ) {
endTime = heater_end_Time.state
}
var totalRuntime = 0
if (heater_Runtime_Total.state instanceof QuantityType) { // it's the STATE of interest
totalRuntime = (heater_Runtime_Total.state as QuantityType).toUnit("s").intValue // get the time in number of seconds
} // but what if it wasn't a Quantity? That's okay, variable stays zero
// rest of your code
Validation issues found in configuration model 'heater_runtime_three.rules', using it anyway:
QuantityType is a raw type. References to generic type QuantityType<T> should be parameterized
parameterized! is that word?
rule "Calculate Heater Runtime"
when
Item MainHeater changed
then
// get the current variable states
// but what if we've never run before?
var startTime = now
if ( !(heater_Start_Time.state instanceof UndefType) ) { // not NULL or UNDEF
startTime = heater_Start_Time.state
}
var endTime = now
if ( !(heater_End_Time.state instanceof UndefType) ) {
endTime = heater_End_Time.state
}
var totalRuntime = 0
if (heater_Runtime_Total.state instanceof QuantityType) { // it's the STATE of interest
totalRuntime = (heater_Runtime_Total.state as QuantityType).toUnit("s").intValue // get the time in number of seconds
} // but what if it wasn't a Quantity? That's okay, variable stays zero
// rest of your code
if(MainHeater == OFF){
endTime = now
heater_End_Time.postUpdate(endTime)
}
else if(MainHeater == ON){
startTime = now
heater_Start_Time.postUpdate(startTime)
}
else {
return;
}
if(startTime.isBefore(endTime)){
var runtime = java.time.Duration.between(startTime, endTime)
logInfo("Heater", "Heater Duration in Minutes - " + runtime.toMinutes)
totalRuntime = totalRuntime + runtime.toSeconds
heater_Runtime_Total.postUpdate(totalRuntime.toString+" s")
}
end
If you do need to use Time, you’ll have to import it and I’m not sure I can find where to import it from right now. It’s always a pain to find because some units are created by the OH project and others are maintained by the upstream library.
Configuration model 'heater_runtime_three.rules' has errors, therefore ignoring it: [17,60]: no viable alternative at input '*'
rule "Calculate Heater Runtime"
when
Item MainHeater changed
then
// get the current variable states
// but what if we've never run before?
var startTime = now
if ( !(heater_Start_Time.state instanceof UndefType) ) { // not NULL or UNDEF
startTime = heater_Start_Time.state
}
var endTime = now
if ( !(heater_End_Time.state instanceof UndefType) ) {
endTime = heater_End_Time.state
}
var totalRuntime = 0
if (heater_Runtime_Total.state instanceof QuantityType<*>) { // it's the STATE of interest
totalRuntime = (heater_Runtime_Total.state as QuantityType<*>).toUnit("s").intValue // get the time in number of seconds
} // but what if it wasn't a Quantity? That's okay, variable stays zero
if(MainHeater == OFF){
endTime = now
heater_End_Time.postUpdate(endTime)
}
else if(MainHeater == ON){
startTime = now
heater_Start_Time.postUpdate(startTime)
}
else {
return;
}
if(startTime.isBefore(endTime)){
var runtime = java.time.Duration.between(startTime, endTime)
logInfo("Heater", "Heater Duration in Minutes - " + runtime.toMinutes)
totalRuntime = totalRuntime + runtime.toSeconds
heater_Runtime_Total.postUpdate(totalRuntime.toString+" s")
}
end
Validation issues found in configuration model 'heater_runtime_three.rules', using it anyway:
Cannot perform instanceof check against parameterized type QuantityType<Number>
Cannot perform instanceof check against parameterized type QuantityType<Number>
Cannot perform instanceof check against parameterized type QuantityType<Number>
Configuration model 'heater_runtime_three.rules' has errors, therefore ignoring it: [18,60]: no viable alternative at input 'Time'
[19,68]: no viable alternative at input 'Time'
Perhaps we should have made it clearer that the thing to change would be the thing reporting the error.
if (heater_Runtime_Total.state instanceof QuantityType) {
Leave that one alone. It doesn’t care what flavour of QuantityType.
totalRuntime = (heater_Runtime_Total.state as QuantityType<DateTime>).toUnit("s").intValue
or
totalRuntime = (heater_Runtime_Total.state as QuantityType<Number>).toUnit("s").intValue
Got it. I made the changes with both and . Both will load with no errors but neither seem to produce any results. I added some logging (maybe not very well) but i get nothing when the heater turns on and the rule fires. Here’s the updated along with the items just to validate.
//Calculate Heater Time
rule "Calculate Heater Runtime"
when
Item MainHeater changed
then
// get the current variable states
// but what if we've never run before?
var startTime = now
if ( !(heater_Start_Time.state instanceof UndefType) ) { // not NULL or UNDEF
startTime = heater_Start_Time.state
}
var endTime = now
if ( !(heater_End_Time.state instanceof UndefType) ) {
endTime = heater_End_Time.state
}
var totalRuntime = 0
if (heater_Runtime_Total.state instanceof QuantityType) { // it's the STATE of interest
totalRuntime = (heater_Runtime_Total.state as QuantityType<Number>).toUnit("s").intValue // get the time in number of seconds
} // but what if it wasn't a Quantity? That's okay, variable stays zero
// rest of your code
if(MainHeater == OFF){
endTime = now
heater_End_Time.postUpdate(endTime)
}
else if(MainHeater == ON){
startTime = now
heater_Start_Time.postUpdate(startTime)
logInfo("main heater start time", "Main Heater Start Time :"+heater_Start_Time.state.toString)
}
else {
return;
}
if(startTime.isBefore(endTime)){
var runtime = java.time.Duration.bet/ween(startTime, endTime)
logInfo("Heater", "Heater Duration in Minutes - " + runtime.toMinutes)
totalRuntime = totalRuntime + runtime.toSeconds
heater_Runtime_Total.postUpdate(totalRuntime.toString+" s")
logInfo("Greenhouse Heater Total Time",heater_Runtime_Total.state)
}
end
Trying to log the total time but nothing shows in the log. it shows that heater turns ON and OFF when I switch it on and off but nothing logs.