Timer to limit rule triggering not working

I have created a rule to open or close windows depending on the outside and inside temperatures, In addition the rule is only active when the kids are not asleep and I can stop execution of the “then” part via a switch.
In order to not have this rule trigger with every temperature change but only every hour I have included a 60 minute timer that must be “null” for the rule to fire.
For some (probably trivial) reason this last part does not work. Any help would be much appreciated.

var Timer timer = null
rule "Lüften, wenn innen wärmer als draußen"
    when
        Item    Temperature_FF_Bedroom changed or
        Item    Temperature_Garden_Terrace changed
    then
        var Number InsideTemperature = Temperature_FF_Bedroom.state as DecimalType
        var Number OutsideTemperature = Temperature_Garden_Terrace.state as DecimalType
        val    dT=2
            if    (OutsideTemperature <= (InsideTemperature - dT)    &&
                (InsideTemperature >= 21)                         &&                        
                (timer == null)                                    &&    
                (Kids_awake.state == ON)                        &&                            
                (ClimateControl_interrupt.state == OFF))            
            {
                logInfo("FILE", "Too warm inside, opening windows")
                sendTelegram("Jonas", "Too warm inside, opening windows")
                sendCommand(Windows_All, UP)
                createTimer(now.plusMinutes(60), [|
                    logInfo("FILE", "Timer expired")
                    timer = null
                    ])                
            }
            if    (OutsideTemperature > (InsideTemperature + dT)    &&
                (InsideTemperature >= 22)                         && 
                (timer == null)                                    &&
                (Kids_awake.state == ON)                        &&
                (ClimateControl_interrupt.state == OFF))            
            {
                logInfo("FILE", "Too warm outside, closing windows")
                sendTelegram("bot1", "Too warm outside, closing windows")
                sendCommand(Windows_All, DOWN)
                createTimer(now.plusMinutes(60), [|
                    logInfo("FILE", "Timer expired")
                    timer = null
                    ])
            if    (OutsideTemperature < (InsideTemperature)    &&
                (InsideTemperature < 20)                         && 
                (timer == null)                                    &&
                (Kids_awake.state == ON)                        &&
                (ClimateControl_interrupt.state == OFF))            
            {
                logInfo("FILE", "Too cold outside, closing windows")
                sendTelegram("bot1", "Too cold outside, closing windows")
                sendCommand(Windows_All, DOWN)
                createTimer(now.plusMinutes(60), [|
                    logInfo("FILE", "Timer expired")
                    timer = null
                    ])
            }
            else {
        logInfo("FILE", "Timer rescheduled")
        timer.reschedule(now.plusMinutes(60))
    }
}            
end

This is good, to hold a Timer by name so that you can look at it later. Personally I would choose a name you are less likely to use somewhere else as well, var Timer windowtimer = null

This is not good. A Timer is created, but it is anonymous and you cannot get at it later, not even to see if it is null.
You want to put that Timer into the variable you declared to hold it
timer = createTimer(now.plusMinutes(60), [ |

Then the handle ‘timer’ will work later.

Or if you do change the name
windowtimer = createTimer(now.plusMinutes(60), [|
// do stuff
windowtimer = null
])
so it is clear which are names of your choice (rather than special magic words)

@rossko57’s comments are spot on.

If you want to side step the whole timer thing entirely you can use the Expire Binding.

Switch WindowTimer { expire="60m,command=OFF" }

Then the rule becomes:

rule "Lüften, wenn innen wärmer als draußen"
    when
        Item    Temperature_FF_Bedroom changed or
        Item    Temperature_Garden_Terrace changed
    then
        var Number InsideTemperature = Temperature_FF_Bedroom.state as DecimalType
        var Number OutsideTemperature = Temperature_Garden_Terrace.state as DecimalType
        val    dT=2
            if    (OutsideTemperature <= (InsideTemperature - dT)    &&
                (InsideTemperature >= 21)                         &&                        
                (WindowTimer.state == OFF)                                    &&    
                (Kids_awake.state == ON)                        &&                            
                (ClimateControl_interrupt.state == OFF))            
            {
                logInfo("FILE", "Too warm inside, opening windows")
                sendTelegram("Jonas", "Too warm inside, opening windows")
                sendCommand(Windows_All, UP)
                WindowTimer.sendCommand(ON)
            }
            if    (OutsideTemperature > (InsideTemperature + dT)    &&
                (InsideTemperature >= 22)                         && 
                WindowTimer.state == OFF                                    &&
                (Kids_awake.state == ON)                        &&
                (ClimateControl_interrupt.state == OFF))            
            {
                logInfo("FILE", "Too warm outside, closing windows")
                sendTelegram("bot1", "Too warm outside, closing windows")
                sendCommand(Windows_All, DOWN)
                WindowTimer.sendCommand(ON)
            if    (OutsideTemperature < (InsideTemperature)    &&
                (InsideTemperature < 20)                         && 
                WindowTimer.state == OFF                                    &&
                (Kids_awake.state == ON)                        &&
                (ClimateControl_interrupt.state == OFF))            
            {
                logInfo("FILE", "Too cold outside, closing windows")
                sendTelegram("bot1", "Too cold outside, closing windows")
                sendCommand(Windows_All, DOWN)
                WindowTimer.sendCommand(ON)
            }
            else {
        logInfo("FILE", "Timer rescheduled")
        WindowTimer.sendCommand(ON)
    }
}            
end

Furthermore, I think you code could be a little easier to read if you use a little bit of nesting of if statements (this is a rare case of that).

    if(WindowTimer.state == OFF && Kids_awake.state == ON && ClimateControl_interrupt.state == OFF){
        WindowTimer.sendCommand(ON)

        if(OutsideTemperature <= (InsideTemperature - dT) && InsideTemperature >= 21) {
            logInfo("FILE", "Too warm inside, opening windows")
            sendTelegram("Jonas", "Too warm inside, opening windows")
            sendCommand(Windows_All, UP)
        }
        else if(OutsideTemperature > (InsideTemperature + dT) && InsideTemperature >= 22) {
            logInfo("FILE", "Too warm outside, closing windows")
            sendTelegram("bot1", "Too warm outside, closing windows")
            sendCommand(Windows_All, DOWN)
        }
        else if (OutsideTemperature < InsideTemperature) && InsideTemperature < 20) {
            logInfo("FILE", "Too cold outside, closing windows")
            sendTelegram("bot1", "Too cold outside, closing windows")
            sendCommand(Windows_All, DOWN)
        }
      }
    }

Thank you both for your helpful comments! The rule is working now.
Best wishes,
Jonas