OH3 how to blocky this simple thing?

Hola amigos,
another day another oh2.5 to oh3 migration…

I’ve figured out that files are the only way I would go with, as they are unbeatable in terms of flexibility… thanks to docker I can run my production OH2 and play with OH3 migration forever till I’m satisfied…

I found out that rules/scheduler and script would NOT accept anything non-semantic by default (3.1 snapshot 2115), which is bit lame honestly as you need quite a lot of helpers which does not have to be semantic at all… yes it can be avoided by selecting “semantic” item first and then edit item in the next step, but thats… ok i can live with

but how we can achieve this simple DSL rule in blocky?

rule "Cleaning"
when
    Item Service_Clean received command ON
then
    var count = ((if(Service_Clean_Count.state >= 0) Service_Clean_Count.state else 0) as Number).intValue + 1

    Service_Clean_Count.postUpdate(count)
    Service_Clean_Date.postUpdate(now.toString)

    Service_Clean.setLabel("Cleaned today | " + now.toString("dd.MM") + " (" + count + ")")
end

And as I do like idea of having rules defined by UI I’m trying to get used to blocky … well my surprise, there is nothing like time functions in there?

So far I’ve got this

var count;


count = itemRegistry.getItem('Service_Clean_Count').getState();
count = (typeof count == 'number' ? count : 0) + 1;
events.postUpdate('Service_Clean_Count', count);
events.postUpdate('Service_Clean_Date', 'value');

But can’t figue how to add “now” and as well it seems there is no possibility to manipulate label? or is it?
should I just fire script instead where I put those 4 lines of DSL code instead?

This got me thinking… is UI rule definiton meant to be for regular joe? IFTTT ? as It does looks like it cannot offer anything near flexible as DLS or jython is…

I really do like scheduling (there is a bug as well, as you need to define rule from Scheduling or it’s not “scheduled” at all) but these limitations of UI pull me back a bit …

or I’m missing something very obvious here?

(not rant, not complain, just genuine question)

and

are mutually exclusive. If text configs “are unbeatable in terms of flexibility” (which could be argued with) why would you not create your rules in text files too?

Blockly is only very basic and not complete. It’s also missing access to Actions and Timers and such.

Yes, until Blockly becomes more complete it’s not really going to be viable for all your rules. Only the simplest of rules that don’t need to do much more than do a little math and update or command an Item.

Even when it’s complete, it’s never going to be as flexible as writing the actual code. That’s the problem. It can be simple and easy to understand and limited in capability or it can be flexible and powerful but harder to use and understand. You can’t have both.

It’s not a bug. If you don’t create it from the Scheduling tab, you need to add a “Schedule” tag to the Rule. Note that it can only understand cron and time triggered rules. It cannot understand Ephemeris or Astro type triggered rules.

If you create a rule in text you can define the Schedule tag when you create the Rule (cannot be done in Rules DSL .rules files though).

kind of is, cos adding Schedule tag is not working after rule is created :wink: … anyway that’s not a boomer.

@rlkoshak as far as I was able to find, JSR233 is not yet in OH3 (helper libraries are not yet done (?) ) and DSL are not supported eg. not fully working in same way as in OH2.

so … till OH3 will mature a bit, what’s correct way to do rules in?
I must admit I’m not following every discussion about OH3 so maybe it was mentioned already …

It works for me.

I did not create that Rule from the Schedule page. I added the tag after the fact.

The Helper Libraries are not required to write in other languages. They just make doing so easier. You can write rules in any of the supported languages now in text files or in the UI.

Rules DSL doesn’t support libraries so there is no such thing as Helper Libraries for that. But Rules DSL is every bit as supported in OH 3 as it was in OH 2.5. With only a few minor changes (e.g. move from Joda to ZonedDateTime) any .rules files that ran in 2.5 will work in 3.0. And if you choose to, you can write Script Conditions and Script Actions with Rules DSL in the UI.

There is no “correct” way. It depends on what you are trying to do. If you are moving from OH 2.5 to OH 3 the most expedient way would be to make the few minor changes to your existing .rules files required to adjust to the breaking changes in Rules DSL.

If you want to write rules in the UI, you’ll have to recreate your Rules anyway. But most of what the helper libraries provide is making the creation of rules easier. In the UI that’s all done for you so it’s very easy to create rules in the UI using JS, Python, or Groovy without the Helper Libraries. Especially if you are recreating Rules DSL rules since Rules DSL has always and will always be less capable as a language.

If you opt for ECMAScript now is new Date() and I’d advise against changing labels - these are your system’s configuration, the average rules except in some circumstances should only manipulate what the user themselves can do i.e. item states. The DSL language is nice and all but if you choose another language, like Python, JS or Groovy these are thoroughly documented.

You also have a “scratchpad” where you can type some code, hit Ctrl-S then Ctrl-R and have it immediately run, that’s helpful while debugging.

For ECMAScript you’ll even get some autocompletion right in the UI.

image

Also at least with Nashorn (and until a GraalVM script engine becomes the primary way and replaces it and this syntax will change) you can load external libraries, maybe not all, but some work like Day.js, a powerful date manipulation library:
Disclaimer: Loading your libraries from a CDN is not necessarily advisable except if your rule doesn’t run often!

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

load("https://unpkg.com/dayjs@1.8.21/dayjs.min.js");
load("https://unpkg.com/dayjs@1.8.21/plugin/relativeTime.js");
dayjs.extend(dayjs_plugin_relativeTime);

logger.info('The year started ' + dayjs().startOf('year').fromNow());

(I jumped through hoops to get the relativeTime plugin loaded in Nashorn following Loading plugin in the browser · Day.js but it ended up working:)

 [INFO ] [org.openhab.rule.scratchpad          ] - The year started 5 days ago

You can limit it by checking if some variable that the library creates on this is undefined and only load if it is. I was doing that for all my personal libraries for awhile until I lost a bunch of time because I was changing the library and I couldn’t figure out why the changes were not picked up until I changes and saved the rule. I hate it when it does what I tell it to do instead of what I mean for it to do. :smiley:

thanks for your time!

it seems my chrome is broken, I don’t have any (except code highlighting) … will try in something else tho

This is really a pitty - especially Timers are a main feature needed in scripts and rules - the possibility to react to an event not immediately.

I have to admit, that I still have not fully understood the concept behind Blockly and the interaction of it with other programming languages. But during search I stumbled across the fact, that ioBroker uses a Blockly implementation/integration (what is correct?), that already includes Timers (there called Timeouts). Anyway to port this to OH, or is it something connected to the underlying programming language or system?

Yours,
KaDe

I don’t know if it’s available yet but there is a debounce profile that would handle this case without need for a rule at all. There is also Expire. And of course, you can write a rule textual instead of graphically.

In OH 3 the Blockly converts to JavaScript. You can actually see the JavaScript by clicking on the code tab. That’s all the Blockly is, it presents a graphical representation of some standard programming language. As such, anything that can be done in the underlying language can theoretically be done in Blockly. But you have to set Blockly up to support that.

I don’t know the details about how Blockly is configured but yes, it’s possible to do just about anything in Blockly that you can do in the underlying language. I didn’t say Blockly could never support creating Timers. It just doesn’t do so yet. It will take someone who has the time and knowledge to implement it.

But just because Blockly for ioBroker does something doesn’t really mean anything. What needs to be done is to configure a new block that converts to the proper JavaScript code for openHAB.

Frankly, the fact that we have Blockly support at all was thrown in at the last minute and as such it works surprisingly well. But there wasn’t time to make it complete. I’m sure volunteers to work on it would be greatly appreciated.

can you point me where is this mentioned?
In list which is in the docs, i can’t really see anything like that
Thanks

Actually, now that I look for it, it’s not in core. It was implemented in Python rules code to create the debounce profile. I remember being excited that one can create a custom profile in rules code but I can’t remember where that discussion took place. @CrazyIvan359, I think you were part of that conversation, does that bring any recollections?

It’s hysteresis that was implemented in core as a profile, not debounce. They are similar but not the same.

In the mean time, I’ve both a python (requires the Helper Libraries) and JavaScript YAML rule (doesn’t require the Helper Libraries) that implements debounce based on Item metadata that can be found at GitHub - rkoshak/openhab-rules-tools: Library functions, classes, and examples to reuse in the development of new Rules.. For UI Rules users you can just copy the YAML into a new rule’s code tab (until we get an import/export feature for YAML files and/or a marketplace to distribute stuff like this).

:+1:

Could be a good idea someday to start a thread/GitHub issue for the purpose of asking what’s missing, and coming up with code snippets that could be converted to Blockly blocks. I don’t know how to create a timer in an openHAB JS action in the best way possible, so input would be appreciated. Then making the block is not that hard:

And Blockly can also output Python code, so when there’ll eventually be an “eject” feature to stop using Blockly and continue with code, if all blocks have their Python code generation equivalent you could choose to continue coding in Python.

It’s a little tricky actually. We would probably want to have a reference to the Timer persist across runs of the rule right? So it can be tested to see if it’s still running and cancelled or rescheduled.

Given that it would be something like:

/** Goes at the top, doesn't need to be imported more than once */
var ScriptExecution = Java.type("org.openhab.core.model.script.actions.ScriptExecution");

/** Function to run when the timer goes off */
var runme = function() {
    // stuff to do when the timer expires
}

/** Create the Timer */
this.myTimer = ScriptExection.createTimer(now.plusSeconds(10), runme);

However, I’ve discovered that if you want to make sure that certain variables are fixed inside the runme function, you need to do something like

/** Goes at the top, doesn't need to be imported more than once */
var ScriptExecution = Java.type("org.openhab.core.model.script.actions.ScriptExecution");

/** Function to run when the timer goes off */
var runmeGenerator = function(itemName) {
    // stuff to do when the timer expires
}

/** Create the Timer */
this.myTimer = ScriptExection.createTimer(now.plusSeconds(10), runme(event.itemName));

The problem is if the rule runs again it runs with the same context and event.itemName will become overwritten by the time the Timer runs. By using a function generator, the itemName gets fixed and won’t be overwritten (I learned this the hard way). But for Blockly I think we might be able to hide that by using a function generator behind the scenes and pass in all the normal stuff like event as arguments by default.

But we also would need to support throw away Timers (i.e. we don’t save it to a variable) and Timers that we want to keep in a variable and check later. So this might require a new variable block and two versions of the Timer block? I’ve never done Blockly myself but my son has been doing Scratch so I’m a little familiar with how the concept is supposed to work.

I’ll go open an issue and start to populate it. Most of the other stuff that’s missing is going to be much easier than Timers I think.

Issue opened and populated with my first list:

@rlkoshak I was involved and excited! I don’t remember the example that was used and setup completely though. I should look at that again now that I’m actually getting around to working on my own rules instead of helper libs and stubs lol.

FWIW, to build the blocks in the file above I mostly used this: Blockly Demo: Blockly Developer Tools - that’s blockly used to build blockly blocks :man_shrugging:

And if there’s need to go deeper in the code, or include some library that’s already been made, those are also good resources:

1 Like

Example:

Wow, I am really impressed about the discussion I started. I really, really appreciate this. Reading through your posts I started remembering how difficult for me it was, to fiddle out the validity of variables through several instances of a rule (so e.g. the closure of a window would stop the timer, that was started by opening it).

Since the enhancements thread was opened I guess this thread could be closed.

Yours, KaDe

I don’t think that not having timers is solely a blockly issue - blockly is extendable and some have apparently made timers (Help!!! Blockly timer - Domoticz), seems more an integration/implemenation issue in oh3. Anyway I’ll try rules, but sequencing and time based events is a large part of automation. It shouldn’t be a “Fight” for new users to do rudimentary things in OH3.

As I said above:

Blockly is only very basic and not complete. It’s also missing access to Actions and Timers and such.

As such, anything that can be done in the underlying language can theoretically be done in Blockly. But you have to set Blockly up to support that.

it’s possible to do just about anything in Blockly that you can do in the underlying language. I didn’t say Blockly could never support creating Timers. It just doesn’t do so yet .

Where in that do I imply that this is “solely a blockly issue” or that it can’t be done. To me at least I thought I was pretty clear that these things like Timers just haven’t been implemented yet. And I actually did something about it. I opened an issue that is actively being worked to add much of what is missing from the Blockly implementation for OH 3 (see link above), including timers.

I had a conversation with the developer (see above) about some of the gotchas and related issues. While I’m not implementing the code I’m definitely following it as it’s implemented and will review where I’m able.

Frankly, based on how I’ve seen OH 2 roll out and now how OH 3 rolled out, new users are never going to be happy. Maybe it’s because they don’t know the history. They don’t know how far we have actually come in usability over the years. They don’t know how much more useful, how much easier everything is compared to older versions. And they don’t see how much freaking work was, is, and continues to be done to make it easier to use. All they see is “I don’t understand it, you need to fix it” and frankly it’s exhausting, angering, and demoralizing.

1 Like

Sorry I thought you were calling blockly is basic rather than, it has only be implement with basic capability.

OH3 is pretty solid, its come very far, but to be frank (and I am a software dev) no one cares what we’ve done, they care what the current thing can do for them * now * in an easy fast way, that’s sadly the world we live in. I know how demoralizing it can be. New users won’t always be happy, but they can be happier in the most painful areas.

If I didn’t know linux, networking and JS already, I’d be lost from the get go. OH is still very much a tinker-er environment - abstract worlds like “thing” and “item” and the underlying “binding” probably need to be forgotten from a general users UI. Blockly is a decent attempt to move some stuff out of text files, but under implemented - in that - easy to setup timers are essential - every “custom smart device app from kasa to lutron” has schedules and sequencing of some sort.

We all want this platform to succeed even more than it already has and I appreciate the effort that’s made it possible.