Problems with Blockly Timers

Hello community,

within the last weeks I have installed openhab 3.2 on my OMV-Server, where it runs within an docker container. So far so good. But to switch off my currently used openHabian, I have to transfer my rules to the new OpenHab instance. For this I tried to use blockly and “recode” the rules grafically … and now I run into problems.

What should the rule do? Our guest toilet has a switch and a motion detector. The aim is, that the light will go off automaticaly (when switch on befor by switch or motion detection) by either switch or timeout (time where no motion or presence was detected).

So here are my rule definitions …

and the blockly code …

and the gerenated Code

var defaultBirghntness, autoOffTime, currentBrightness;

if (typeof this.timers === 'undefined') {
  this.timers = [];
}

var zdt = Java.type('java.time.ZonedDateTime');

var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);

var scriptExecution = Java.type('org.openhab.core.model.script.actions.ScriptExecution');


defaultBirghntness = 75;
autoOffTime = 1 * 20;
currentBrightness = itemRegistry.getItem('HUEWC_Helligkeit').getState();
if (typeof this.timers['timeout_Timer'] !== 'undefined' && this.timers['timeout_Timer'].isRunning()) {
  if (itemRegistry.getItem('HuemotionsensorWC_Bewegung').getState() == 'OFF') {
    events.sendCommand('HUEWC_Helligkeit', '0');
    if (typeof this.timers['timeout_Timer'] !== 'undefined') {
      this.timers['timeout_Timer'].cancel();
      this.timers['timeout_Timer'] = undefined;
    }
  } else {
    if (typeof this.timers['timeout_Timer'] !== 'undefined') { this.timers['timeout_Timer'].reschedule(zdt.now().plusSeconds(autoOffTime)); }
  }
} else {
  if (currentBrightness == '0') {
    logger.error('WC Light ON');
    events.sendCommand('HUEWC_Helligkeit', defaultBirghntness);
  }
  if (typeof this.timers['timeout_Timer'] === 'undefined' || this.timers['timeout_Timer'].hasTerminated()) {
    this.timers['timeout_Timer'] = scriptExecution.createTimer(zdt.now().plusSeconds(autoOffTime), function () {
      logger.error('Timeout Timer retriggered?');
      if (itemRegistry.getItem('HuemotionsensorWC_Bewegung').getState() == 'OFF') {
        events.sendCommand('HUEWC_Helligkeit', '0');
        if (typeof this.timers['timeout_Timer'] !== 'undefined') {
          this.timers['timeout_Timer'].cancel();
          this.timers['timeout_Timer'] = undefined;
        }
      } else {
        if (typeof this.timers['timeout_Timer'] !== 'undefined') { this.timers['timeout_Timer'].reschedule(zdt.now().plusSeconds(autoOffTime)); }
      }
      })
  }
}

What works is, that the light will be sitched on by switch or motion detector and will go off after the timeout time (currently for test purpose only 20s). What not work is to switch of the light befor the timeout will be reached.

An other problem I’ve discovered is, that the log messages will no appear within the events.log file …

Has anyone an idear, where the mistake is?
Thanks, best regards and stay healthy
Stef

After reading the timer manual again I come to the conflusion that it is not possible to create someting similar to the following code with the blockly interface

rule "WC_LightON"
    when   
        Item HueSensMotion2 changed to ON or
		Item LCN_WC_Relay_HUE_WC_Switch changed from ON or
		Item LCN_WC_Relay_HUE_WC_Switch changed from OFF 
    then {
		logInfo("WC-Rule","Triggered")
		val currBrightness = HueWCLight.getStateAs(PercentType) as Number // get the brightness

		if (WC_Auto_OFF_Timer === null || WC_Auto_OFF_Timer.hasTerminated() ) {
			if (HueWCLight.state == 0) {
				sendCommand(HueWCLight, WC_WC_Brightness_Default)
				logInfo("WC-Rule", "switched ON by either switch or BWM.")
			}
			
			WC_Auto_OFF_Timer = createTimer(now.plusSeconds(AutoOffTime), [|
				if (HueSensMotion2.state == OFF) {
					sendCommand(HueWCLight, OFF)
					WC_Auto_OFF_Timer = null
					logInfo("WC-Rule", " switch light OFF, because timer has finished.")
				} else {
					WC_Auto_OFF_Timer.reschedule(now.plusSeconds(AutoOffTime))
					logInfo("WC-Rule","ReSchedule Timer, because WC still occupied.")
				}
			])
		} else {
			logInfo("WC-Rule", "retrigger path.")

			if (triggeringItem.name == "LCN_WC_Relay_HUE_WC_Switch") {
				sendCommand(HueWCLight, OFF)
				WC_Auto_OFF_Timer.cancel
				WC_Auto_OFF_Timer = null
				logInfo("WC-Rule","OFF by switch.")
			}
			else {
				WC_Auto_OFF_Timer.reschedule(now.plusSeconds(AutoOffTime))
				logInfo("WC-Rule","ReSchedule Timer because of presence.")
			}
   	    }
	}
end

If someone has an  idear how to map this code with blockly it would be fine toi share this.

Thanks and best regards
Stef

Here is another version to solve this problem … but switching off the light manually won’t work and I don’t know why …

var defaultBirghntness, autoOffTime, currentBrightness;

var scriptExecution = Java.type('org.openhab.core.model.script.actions.ScriptExecution');

var zdt = Java.type('java.time.ZonedDateTime');

if (typeof this.timers === 'undefined') {
  this.timers = [];
}


defaultBirghntness = 75;
autoOffTime = 1 * 20;
currentBrightness = itemRegistry.getItem('HUEWC_Helligkeit').getState();
if (itemRegistry.getItem('HUEWC_Helligkeit').getState() < '5') {
  events.sendCommand('HUEWC_Helligkeit', defaultBirghntness);
  if (typeof this.timers['timeout_Timer'] === 'undefined' || this.timers['timeout_Timer'].hasTerminated()) {
    this.timers['timeout_Timer'] = scriptExecution.createTimer(zdt.now().plusSeconds(autoOffTime), function () {
      if (itemRegistry.getItem('HuemotionsensorWC_Bewegung').getState() == 'OFF') {
        events.sendCommand('HUEWC_Helligkeit', '0');
        if (typeof this.timers['timeout_Timer'] !== 'undefined') {
          this.timers['timeout_Timer'].cancel();
          this.timers['timeout_Timer'] = undefined;
        }
      } else {
        if (typeof this.timers['timeout_Timer'] !== 'undefined') { this.timers['timeout_Timer'].reschedule(zdt.now().plusSeconds(autoOffTime)); }
      }
      })
  }
} else if (itemRegistry.getItem('HuemotionsensorWC_Bewegung').getState() == 'OFF') {
  events.sendCommand('HUEWC_Helligkeit', '0');
  if (typeof this.timers['timeout_Timer'] !== 'undefined') {
    this.timers['timeout_Timer'].cancel();
    this.timers['timeout_Timer'] = undefined;
  }
} else {
  if (typeof this.timers['timeout_Timer'] !== 'undefined') { this.timers['timeout_Timer'].reschedule(zdt.now().plusSeconds(autoOffTime)); }
}

Your rule should have 3 scenarios:

  1. Motion = turn on the light, set/reschedule timer
  2. Switch on = turn on the light, set timer
  3. Switch off = turn off the light, cancel timer

In your script you are handling only the motion cases, that’s why switch off is not working.
You would need to update your if/else section

Hello Matze0211

thanks for your support. The 3rd szenario you mentioned is implemented in the “else if” pass, because … if the motion detector has not fired (off) then the other trigger have fired and the other triggers are the switch (relaized by a state toggle).

Maybe I’m wrong, but this was the idear behind this implementation.

Thanks and best regards
Stef

PS: Don’t be confused about the trigger for the switch. The switch is an LCN module, where I just toggle the state of an relay, when the switched ist pressed short.

Maybe just add some logging before the if block of your relevant items state and within reach part of the if block to see what’s happening and see if the IF, ELSE IF or ELSE block is executed.

Also you could use received command and triggering item variables to better react on each scenario

I tried to place some logging information inside of the code but I can’t see any logging output in the log, which I viewed with

tail -f events.log

… I see all the events that should trigger the rule.

So I tried a workaround and manipulate the brightness of the bulb instead as well …

But again, I can’t see any

send commands

The code seems to look good

var defaultBirghntness, autoOffTime, currentBrightness, dummy;

var scriptExecution = Java.type('org.openhab.core.model.script.actions.ScriptExecution');

var zdt = Java.type('java.time.ZonedDateTime');

if (typeof this.timers === 'undefined') {
  this.timers = [];
}

var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);


defaultBirghntness = 75;
autoOffTime = 1 * 20;
currentBrightness = itemRegistry.getItem('HUEWC_Helligkeit').getState();
if (itemRegistry.getItem('HUEWC_Helligkeit').getState() < '5') {
  events.sendCommand('HUEWC_Helligkeit', defaultBirghntness);
  if (typeof this.timers['timeout_Timer'] === 'undefined' || this.timers['timeout_Timer'].hasTerminated()) {
    this.timers['timeout_Timer'] = scriptExecution.createTimer(zdt.now().plusSeconds(autoOffTime), function () {
      if (itemRegistry.getItem('HuemotionsensorWC_Bewegung').getState() == 'OFF') {
        events.sendCommand('HUEWC_Helligkeit', '0');
        if (typeof this.timers['timeout_Timer'] !== 'undefined') {
          this.timers['timeout_Timer'].cancel();
          this.timers['timeout_Timer'] = undefined;
        }
      } else {
        if (typeof this.timers['timeout_Timer'] !== 'undefined') { this.timers['timeout_Timer'].reschedule(zdt.now().plusSeconds(autoOffTime)); }
      }
      })
  }
} else if (itemRegistry.getItem('HuemotionsensorWC_Bewegung').getState() == 'OFF') {
  events.sendCommand('HUEWC_Helligkeit', '0');
  if (typeof this.timers['timeout_Timer'] !== 'undefined') {
    this.timers['timeout_Timer'].cancel();
    this.timers['timeout_Timer'] = undefined;
  }
} else {
  if (itemRegistry.getItem('HUEWC_Helligkeit').getState() >= '0') {
    logger.info('ReTrigger by motion detection');
    dummy = itemRegistry.getItem('HUEWC_Helligkeit').getState();
    events.sendCommand('HUEWC_Helligkeit', (dummy - 1));
  }
  if (typeof this.timers['timeout_Timer'] !== 'undefined') { this.timers['timeout_Timer'].reschedule(zdt.now().plusSeconds(autoOffTime)); }
}

From my point of view the rule will not be triggered after started once … but … if I retrigger the motion detection, while the light is on, the rule will be retriggered. But this can also happend within the code that should be executed, when the timer ist finished …

Add some logging BEFORE the IF part and include the state of the items that are relevant into the log output, then you know what’s going on.

If you just have logging in the else part and this
part is not executed, then you do not see anything in the eventslog.

Also instead of tail -f you can use frontail via webbrowser on port 9001 if you like.

The Docker container does not support the port 9001 to show an logging windows … this is another problem that I have to solve.

But … I demystified the problem … f**k … If you take a look on my first post you can see the “But only if” clause … this prevents the rule from being retriggered, while the light is on … damned.

In my original rule I used on openhabian I used if (triggeringItem.name == …) to distinguish which trigger triggers the rule. Within Blockly I can’t find someting similar. So I can switch off the light manualy only after the motion detector hast released his “motion detected” state …

Do you know how to fuild something like if (triggeringItem.name == …) ?

Thanks, best regards, happy new year and stay healthy
Stef

yes, that’s available in openHAB → Run & Process → contextual info

That’s part of openHABian, not openHAB. It’s a separate third party service called Frontal that outbidded the logs in the browser capability. If not using ooenHABian (e.g. rubbing on Docker), it’s up to you to install and configure Frontal.

There is an “event” block that includes all the JSR223 equivalents to implicit variables. In this case event.itemName.

Thanks for the information … now everything works fine as expected … :wink:

Above you can see the final Blocky-Code …

Thanks for helping, happy new year and stay healthy
Stef

1 Like

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.