Rule example: Engine heater based on temperature

OK I am on my phone got to get back to work I’ll be home in 2 hours

:wink: hehe! no worries Vincent . late night for you!

Hi all, I’m trying to set up a simple rule that aim to switch off the heater when the temperature is >= 22 C.
Below the script, that doesn’t work…
I put as trigger the clima setpoint instead of the measured temperature, in order to force the value manually and see if the script work.
I’ve commented all the unnecessary lines in order to simplify, but still no luck.

Can someone help me?

rule "spegnimento_programmato_clima"

when Item Clima_setpont changed

then

 // if (Temperatura_rilevata == NULL) return; // If no temp do nothing
   // Calculate states
    
 //   if (Clima_acceso_spento.state == NULL) {
 //       Clima_acceso_spento.sendCommand(OFF) // Initialise climaaccesospento to OFF just in case
 //       stato_clima = OFF
  //  } else { 
   //     stato_clima = Clima_acceso_spento.state
 //   }

val temperature = Temperatura_rilevata as Number
var stato_clima
    if (temperature >= 22.0) {
       stato_clima = OFF
    } 
    if (temperature <= 18.0) {
        stato_clima = ON
    }

    // Do the command
    Clima_acceso_spento.sendCommand(stato_clima)

end

Temperatura_rilevata is an Item. An Item carris a whole bunch of stuff, one of which is the state.

val temperature = Temperatura_rilevata.state as Number

1 Like

Thank you very much, It works!

Can I ask you which are the other attribuites that I can use on a item? In this case it is .state and It works, but which are the other possibilities?

1 Like

@rlkoshak Another point: what about to put a timer in order to prevent the heater startup and shutdown continuously? Something like this (I don’t know the sintax and if the function already exist). Is it possible?

if (temperature >= 22.0) {
   stato_clima = OFF
 timer(600000);  //stop cycling for 10 minutes
} 
if (temperature <= 18.0) {
    stato_clima = ON
}

name, names of the groups the item is a member of, if it’s a group item a list of all it’s members, the Item’s label, if you have persistence set up on the item is state at some time in the past, average since, sum since, min/max since, if it’s an Item that can be treated as other types (e.g. Color can be treated as a Switch or a Dimmer) you can get the state as one of those other types.

I strongly recommend a review of the rules docs, the Actions docs, and the design pattern posts on this forum.

Thank you @rlkoshak
I’ve red a lot and I was able to fix some problem in the program.
Now there is another problem I’m unable to solve. I add a second temperature sensor and I make the same, identical program with that sensor. With the first sensor the program work, with the second one not…!
temp_aqara is the one that does not works.
I think oit can be a problem of variable declaration but I can’t solve it. Can you help me?
rule “spegnimento_programmato_clima”

when 

Item temp_aqara changed
or
Item Temperatura_rilevata changed 




then




// inizializzazione delle variabili

val temperature = Temperatura_rilevata.state as Number  //Temperatura_rilevata è una Item, che può avere molti attributi. Va specificato l'attributo .state sennò non funziona
val variabile_temp_aqara = temp_aqara.state as Number
var stato_clima
val variabile_setpoint_clima = Clima_setpont.state as Number

  // logInfo(variabile_setpoint_clima)

if (Temperatura_rilevata == NULL) return; // If no temp do nothing
// Calculate states

if (Clima_acceso_spento.state == NULL) {
   Clima_acceso_spento.sendCommand(OFF) // Initialise climaaccesospento to OFF just in case
   stato_clima = OFF
  }  
else { 
  stato_clima = Clima_acceso_spento.state
  }
   
// Controllo della temperatura

    if (temperature >= 23.0) {
    stato_clima = OFF
    } 
    if (temperature >= 22.0) {
    variabile_setpoint_clima = 19
    } 
    if (temperature <= 20.0 || variabile_temp_aqara <= 20) {
    stato_clima = ON
    variabile_setpoint_clima = 23
    }
  // logInfo(variabile_setpoint_clima)
  // Do the command
  // Timer non funzionante, da sistemare  createTimer(now.plusSeconds(60)) [ ]
     Clima_acceso_spento.sendCommand(stato_clima) 
     Clima_setpont.sendCommand(variabile_setpoint_clima)

end 

here the log

2020-12-20 19:49:53.150 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model 'temperature.rules', using it anyway:
Type cannot be derived
Assignment to final variable
Assignment to final variable
2020-12-20 19:49:53.212 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model 'temperature.rules'
2020-12-20 19:50:54.061 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model 'temperature.rules', using it anyway:
Type cannot be derived
Assignment to final variable
Assignment to final variable
2020-12-20 19:50:54.114 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model 'temperature.rules'

Type cannot be derived

This means you have a variable defined and do not five it enough information for the rules ending to determine what it’s type is. I’m going to guess that it’s stato_clima. There is nothing there to tell it what type of variable it is. You need to tell it, either by assigning something to it like in the other variables or give it a type on definition.

var OnOfftype stato_clima

Assignment to final variable

When you define something as a value (i.e. using val) you are saying “this is a constant, it should never change.” consequently, you should never see that value on the left side of a = because reassigning a value to the value is changing it.

You have variable_setpoint_clima on the left side of an = in at least two places. If these lines are valid, which they appear to be, variable_setpoint_clima needs to be declared as a variable (i.e. var), not a value.

Since it’s really cold here now I thought I’d bring this thread back to the original topic of engine heaters.

I would like to share the latest version of my rule. The changes are:

  1. Its adapted to OH3, which means that some logic moved out of the script itself and also that some date/time related stuff had to change
  2. My wife is now on a weekly schedule with different start times each day, so I added functionality for that :stuck_out_tongue:

Rule follows. I kick it off at 5 every morning.

var int minutes = (60 - (Utetemperatur.state as QuantityType<Number>).doubleValue * 6).intValue
if(minutes > 120) {
  minutes = 120
}

var departure = now.with(LocalTime.of(8, 00))

switch(now.getDayOfWeek()) {
  case MONDAY: {
    departure = now.with(LocalTime.of(7, 15))
  }
  case TUESDAY: {
    departure = now.with(LocalTime.of(7, 45))
  }
  case WEDNESDAY: {
    departure = now.with(LocalTime.of(5, 45))
  }
  case THURSDAY: {
    departure = now.with(LocalTime.of(8, 45))
  }
  case FRIDAY: {
    departure = now.with(LocalTime.of(6, 15))
  }
  default: {
    logError("engineheater", "This rule is not supposed to be activated today!")    
  }
}

createTimer(departure.minusMinutes(minutes)) [|
  Motorvarmare.sendCommand(ON)
]

It’s probably worth while when posting Rules like these to the forum to post the full rule from the code tab instead of just the Script Actions. That way we can all see the triggers and conditions too. If it’s not a UI rule, include the rule/when/then/end stuff too. I’m finding a lot of users on the forum are not quite understanding the difference and if we can try to be consistent it might be easier for them.

My thinking was that this is not a rule that anyone would want to use out-of-the-box anyway, because you have to tweak it to fit your needs. But you may be right, here comes the entire rule:

triggers:
  - id: "3"
    configuration:
      time: 05:00
    type: timer.TimeOfDayTrigger
conditions:
  - inputs: {}
    id: "2"
    configuration: {}
    type: ephemeris.WeekdayCondition
actions:
  - inputs: {}
    id: "1"
    configuration:
      type: application/vnd.openhab.dsl.rule
      script: >
        var int minutes = (60 - (Utetemperatur.state as
        QuantityType<Number>).doubleValue * 6).intValue

        if(minutes > 120) {
          minutes = 120
        }


        var departure = now.with(LocalTime.of(8, 00))


        switch(now.getDayOfWeek()) {
          case MONDAY: {
            departure = now.with(LocalTime.of(7, 15))
          }
          case TUESDAY: {
            departure = now.with(LocalTime.of(7, 45))
          }
          case WEDNESDAY: {
            departure = now.with(LocalTime.of(5, 45))
          }
          case THURSDAY: {
            departure = now.with(LocalTime.of(8, 45))
          }
          case FRIDAY: {
            departure = now.with(LocalTime.of(6, 15))
          }
          default: {
            logError("engineheater", "It's some other day!")    
          }
        }
          
        createTimer(departure.minusMinutes(minutes)) [|
          Motorvarmare.sendCommand(ON)
        ]
    type: script.ScriptAction

By the way: As you see I’ve used ephemeris here to only run when it’s a week day. Is there any way to tell it to run only on week days that are not holidays? I see a check box for if “it’s a holiday” but not the opposite.

It can be informative to see how the rule is triggered. It may not be exactly what people want but seeing the trigger will give them ideas for how to set it up. And I’m amazed at the number of users who are having difficulty understanding how rules are put together in the UI. More examples is better.

There is a PR to add that. I can’t remember if it’s been merged or not but I would expect to see that in OH 3.1, unless there is a problem with doing that.

1 Like

Ok, now it turns out it didn’t work as I expected anyway. Today it is saturday and the engine heater was turned on. Have I misunderstood the ephemeris “it is a weekday”? I thought it meant that it would not be activated on saturdays or sundays? @rlkoshak, you got any idea?

By the way, is there any way of exiting a rule prematurely? In my switch, where I print out an error if it’s not monday-friday, it seems it would be a good idea to put something that simply aborts the script.

Double check the Ephemeris config to verify that the weekend days are set. In scratchpad rule log out the results to calls to isWeekend.

The best way to handle that is to put it into the condition so the rule doesn’t run in the first place.

Yep, it looks alright in Ephemeris config (saturday and sunday are checked). How do you mean I could check this in the scratchpad?

From the developer sidebar you can bring up a scratchpad Script where you can type in and run some rules code without going to the touble if creating a full rule. It is a great place to quickly get stuff out to see what happens or test things or generate events to test something.

Oh, you mean like that. Well, I can confirm that now.isWeekend() returns true today, so everything seems to work fine there. I guess that means there’s a bug somewhere in the rule condition logic?

Assuming the rule ran after midnight that might be the case.

My findings about this is getting weird. I filed a bug:

1 Like