Is createTimer not working in OH3? Or is it user error?

I am running last night’s snapshot. As I am debugging, I simplified my rule to just be:

rule "Kitchen scene Selection"
when
  Item KitchenLights_Keypad_Button2 changed to OFF
then
  createTimer(now.toInstant().plusMillis(200),
      [| logInfo("KitchenSceneSelection", "Timer fired") ])
end

I tried both syntaxes: with the Procedure as an argument, or next to createTimer. I always get:

[ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'update_patterns-5' failed: An error occurred during the script execution: Could not invoke method: org.openhab.core.model.script.actions.ScriptExecution.createTimer(java.time.ZonedDateTime,org.eclipse.xtext.xbase.lib.Procedures$Procedure0) on instance: null in update_patterns

Are you triggering the rule using the Item or pressing the play button in MainUI? I’m unaware of any reason why that createTimer command would fail. The error is showing that now is a ZonedDateTime which is the only change I’m aware of (it used to be a Joda DateTime).

I think it’s the time part that has changed; “now” is no longer a Joda object. Look at the methods e.g. plusMillis
You didn’t need toInstant when it was a Joda.

That is not what the error is. The error is about being called on “null” and I am already using java.time methods (hence the toInstant()).

That error is kind of a catch all error. You usually see it when something isn’t the right type. But based on the error message the arguments appear to be the right type so something else is going on.

Yes, when using the wrong type one gets a type error. That’s actually one of the few errors that work, and in that case you’re lucky, you even get the fully qualified name of the class.

Also to anser @rlkoshak question, I trigger this using the Pico keypad.

Would switching to Jython or ECMAScript give me better error messages/functionality? That fragment above is as simple as I can think of.

If you are just getting started it wouldn’t be a bad idea to use JavaScript as your language. Some things will not be as straight forward though. A lot has been made easier with the Helper Libraries (https://openhab-scripters.github.io/openhab-helper-libraries/index.html) but I don’t know if the JavaScript helper libraries have been updated to work with OH 3 yet or not. When I first tried them a couple weeks ago they were not.

I am indeed just getting started, and I see that one can write JS directly in the UI too… Python seems better for heavy projects and may be easier to debug with type hints but I don’t think those are available in 2.7? I am a very poor Python programmer, it’s not something I use often. Neither is JS for that matter…

One of the things that seems to not have been done for JS are decorators like @rule, @when etc.? At least if you look at the OH docs?

But what’s that for? As I understand it, it adjusts to UTC. createTimer doesn’t want UTC, the scheduler is operating inthe same timezone as “now”. Have you actually tried without this?

You need an instant to be able to add/substract time units in Java 8.

This isn’t java 8. It’s DSL. Have you actually tried without this?

(I didn’t think OH3 ran under java 8?)

As of this writing here is the state of things on OH 3.

  • If you create your rules through the UI the decorators do not matter. You won’t be using them anyway. The decorators are used to define the rule and rule triggers which is handled in a completely different way when you create rules through the UI. So the decorators only really matter if you plan on working with .py or .js files to build your rules (note even if you create your rules through the UI does not mean you cannot write your own libraries and use libraries from others). Also, you can program rules through the UI using any supported language. When there is an OH 3 compatible Jython add-on you can write your scripts in the UI using Jython. There is already a Groovy add-on if that’s a language you are interested in. Note that even Rules DSL is supported in the UI too.

  • Jython is not yet supported on OH 3. Hopefully soon it will be supported as an add-on. But if you want to get started now, looking at JavaScript might be a better choice.

  • Rules DSL and JavaScript appear to be the only languages that come out-of-the-box. All the other languages look like they will need to be installed separately.

  • The Jython add-on is Python version 2.7. This is a deal breaker to some. But if you will be writing rules in text files instead of the UI, Jython is the most mature in terms of the Helper Libraries and examples here on the forum.

  • No matter what language you choose you will want to download and use the Helper Libraries because a lot of stuff is done for you in Rules DSL that doesn’t get done for you in these other languages and the Helper Libraries make dealing with that stuff easier. For example, here is how to create a Timer in JavaScript without the Helper Libraries:

// ScriptExecution.createTimer
var ScriptExecution = Java.type("org.openhab.core.model.script.actions.ScriptExecution");
var runme = function(){ logger.info("Timer expired!"); }
var ZonedDateTime = Java.type("java.time.ZonedDateTime");
var now = ZonedDateTime.now().plusSeconds(30);
var timer = ScriptExecution.createTimer(now.plusSeconds(1), runme);

I’m moving all of my rules (and libraries https://github.com/rkoshak/openhab-rules-tools) to JavaScript and JSONDB (i.e. built through the UI) and so far I’m pretty happy with the approach. The only limitation I’ve found so far is the inability to share a global variable across multiple scripts (e.g. between two different rules).

I don’t know what type now is in Rules DSL but suspect it’s either a ZonedDateTime or LocalDateTime. If so, as rossko57 indicates, the toInstant() wouldn’t be required. But I also don’t think it’s the problem as the error indicates that createTimer is being passed a ZonedDateTime which is what it needs now.

I think the error message is saying what createTimer() wants as arguments, not what it was actually given.

The DSL is on top of the Java runtime and OH3 switched to java.time (see this tracker), so it’s Java 8 or later (not sure about this exactly, haven’t looked to find out).

This being said, it was user error. I assumed there was a constructor to ZonedDateTime that would take an Instant. There isn’t. The following does work in OH3, I just verified:

createTimer(now.toInstant().plusMillis(200).atZone(now.zone),
    [| logInfo("Hello", "World!") ])

So indeed, the “cannot invoke on null” was a total red herring, and the message was complaining about my Instant not being the proper type. Since I’ve seen different type error messages that made more sense in other contexts, I didn’t double check that (and adding .atZone(now.zone) brings the Instant back to a ZonedDateTime).

1 Like

It might be worth changing the createTimer() API to take an Instant. It would be backwards compatible with the Joda API for adding delays (a common use of timers) and help migration. But there may be reasons not to want that, too.

@rossko57, OH 3 is on Java 11 now (source).

Take a look at the methods of ZonedDateTime (now() in OH3 is a ZonedDateTime)…

createTimer(now.plusNanos(2000000)),
    [| logInfo("Hello", "World!") ])
2 Likes

Yeah that works too. Funny that they added every unit but milliseconds. That’s Java for you.

It will require some extra imports you but you can add millis using

import java.time.temporal.ChronoUnit
...
    dt = ZonedDateTime.now().plus(200, ChronoUnit.MILLIS)

I don’t know why they have nanos but not millis.

I don’t know why they have nanos but not millis.

Java APIs are consistently inconsistent. That’s been true since 1998.

1 Like