[SOLVED] Jython reschedule timer

You’ll need to be more specific, since there are several in this topic. I’ll make two suggestions though, right off the bat. Use the createTimer Action and read the examples in the documentation.

Timer example from @vzorglub 'Nov 19:

if FRIDGEDOORTIMER is not None and not FRIDGEDOORTIMER.hasTerminated()
FRIDGEDOORTIMER.hasTerminated() is always true, once fridgedoortimer_body() is running…
apparantly, a reschedule doesn’t make it evaluate the FRIDGEDOORTIMER.hasTerminated() to false again… Probably, because, before fridgedoortimer_body() has ended, a reschedule is done…
FRIDGEDOORTIMER also needs to be declared global in fridgedoortimer_body() …

I’ve had a door sensor on my fridge for a couple of years (maybe longer) and I’ve never found time to write a rule to check if the door was left open. I saw this thread and thought I’d try and adapt the rule for my needs. So far, I have the following:

import core.items
from core.rules import rule
from core.triggers import when
from core.actions import ScriptExecution
from core.actions import Voice
from org.joda.time import DateTime
from core.actions import Pushover
from core.log import logging, LOG_PREFIX

FRIDGEDOORTIMER = None

    @rule("Fridge Door Opened for more than a minute", description="Fridge Door Opened for more than a minute", tags=["Fridge"])
@when("Item SensorFridgeDoor_DoorSensor changed")
@when("Item fridgeTestSwitch received update")
def fridge_door(event):
        global FRIDGEDOORTIMER
        if ( event.itemState == OPEN ) or ( event.itemState == ON ):
            log = logging.getLogger("org.eclipse.smarthome.model.script.security")
            log.info("SECURITY: Fridge door is open.")
            if FRIDGEDOORTIMER is None or FRIDGEDOORTIMER.hasTerminated():
            FRIDGEDOORTIMER = ScriptExecution.createTimer(DateTime.now().plusMinutes(1), fridgedoortimer_body)
        elif ( event.itemState == CLOSED ) or ( event.itemState == OFF ):
            if FRIDGEDOORTIMER is not None and not FRIDGEDOORTIMER.hasTerminated():
                FRIDGEDOORTIMER.cancel()

def fridgedoortimer_body():
    Pushover.sendPushoverMessage(Pushover.pushoverBuilder("Fridge door has been open for over a minute!"))
        FRIDGEDOORTIMER.reschedule(now.plusSeconds(10))

If I open the fridge door or turn on the test switch I see a message in the log that the fridge door is open but I don’t get a Pushover message. Can anyone suggest what I’m doing wrong?

(Sorry about the formatting and indentation of the code above, whenever I cut and paste from Visual Studio Code to here I end up with blank lines between every line and then when I try and remove the blank lines the indenting goes screwy.)

from core.rules import rule 
from core.triggers import when
from core.actions import ScriptExecution
from core.actions import Voice
from org.joda.time import DateTime
from core.log import logging, LOG_PREFIX
from time import sleep
 
RULE_NAME="SensorTimer"
log=logging.getLogger(LOG_PREFIX+"."+RULE_NAME)

Test_Sensor_Timer=None
woonkamerspeaker_Alarm_Volume=30
save_Woonkamerspeaker_Volume=None
alarm_Fired=False
woonkamerspeaker="chromecast:chromecast:55af8aa2114176d12ad027f3fedd199d"

def GV_Test_Sensor_Timer_body():
    global woonkamerspeaker
    global woonkamerspeaker_Alarm_Volume
    global save_Woonkamerspeaker_Volume
    global Test_Sensor_Timer
    global alarm_Fired
    
    if int(str(items.GV_Woonkamer_Speaker_Volume)) !=woonkamerspeaker_Alarm_Volume:
        log.info("save volume in body") 
        save_Woonkamerspeaker_Volume=int(str(items.GV_Woonkamer_Speaker_Volume))
        events.sendCommand("GV_Woonkamer_Speaker_Volume",str(woonkamerspeaker_Alarm_Volume))  
    alarm_Fired=True   
    log.info("say sensor timer is open. Uncomment next line ")    
    #Voice.say("test timer is open","voicerss:nlNL",woonkamerspeaker)
    if Test_Sensor_Timer is not None:
        Test_Sensor_Timer.reschedule(DateTime.now().plusSeconds(5))
    else: log.info("Test_Sensor_Timer is null!")   
 


@rule(RULE_NAME, description="When sensor is opened for more than 1 minute, do actiob", tags=["sensor","timer"])
@when("Item GV_Test_Sensor_OpenClose changed")
def sensortimer(event):
    log.info("Begin "+RULE_NAME)
    global woonkamerspeaker
    global save_Woonkamerspeaker_Volume
    global Test_Sensor_Timer
    global alarm_Fired
     
    log.info("GV_Test_Sensor_OpenClose= "+str(items.GV_Test_Sensor_OpenClose))
    if save_Woonkamerspeaker_Volume is None:
        save_Woonkamerspeaker_Volume=int(str(items.GV_Woonkamer_Speaker_Volume))    
        log.info("initialising save value"+str(items.GV_Woonkamer_Speaker_Volume))

    if items.GV_Test_Sensor_OpenClose==OPEN:
        log.info("starting volume={}".format(items.GV_Woonkamer_Speaker_Volume))
        save_Woonkamerspeaker_Volume=int(str(items.GV_Woonkamer_Speaker_Volume))
        alarm_Fired=False
        scheduleTime=DateTime.now().plusSeconds(10)
        if Test_Sensor_Timer is None:
            log.info("Creating timer") 
            Test_Sensor_Timer=ScriptExecution.createTimer(scheduleTime,GV_Test_Sensor_Timer_body)
        else:
            log.info("rescheduling timer")
            Test_Sensor_Timer.reschedule(scheduleTime)
    elif items.GV_Test_Sensor_OpenClose==CLOSED:
        if Test_Sensor_Timer is not None:
            if alarm_Fired:
                 log.info("say sensor timer is closed now. Uncomment next line ot hear it ") 
                #Voice.say("De test timer is nu gesloten","voicerss:nlNL",woonkamerspeaker)
            log.info("Cancelling Test_Sensor_Timer")
            Test_Sensor_Timer.cancel()
        log.info("current volume={}".format(items.GV_Woonkamer_Speaker_Volume))
        log.info("save volume={}".format(save_Woonkamerspeaker_Volume)) 
        if int(str(items.GV_Woonkamer_Speaker_Volume)) != save_Woonkamerspeaker_Volume:
                events.sendCommand("GV_Woonkamer_Speaker_Volume",str(save_Woonkamerspeaker_Volume))
        sleep(10) #waiting a little, so GV_Woonkamer_Speaker_Volume has time te updated. 
        log.info("volume at close (should be starting volume)={}".format(items.GV_Woonkamer_Speaker_Volume))
             
             
    log.info("Einde "+RULE_NAME)






def scriptLoaded(*args):
    log.info(RULE_NAME+" loaded.") 

def scriptUnloaded(*args):
    global Test_Sensor_Timer
    if Test_Sensor_Timer is not None:
        Test_Sensor_Timer.cancel() 
        Test_Sensor_Timer=None
    log.info(RULE_NAME+" unloaded.")

This works. for now, I can’t let it crash during testing :wink:
When working with timers, and testing them, be sure to cancel them… Otherwise, they stay in memory.
During my testing and trying, I had to restart OH several times. Therefore, the scriptUnloaded function is interesting, as in that function, you can cleanup the timer…

3 Likes