Extending Blockly with new openHAB commands

Perhaps the Persistence Extensions (openhab-core/PersistenceExtensions.java at main · openhab/openhab-core · GitHub) can be used with this technique as well
(with some very simple controls to provide the function & ZonedDateTime, like “{dropdown average/maximum/minimum…} since {int} {dropdown:seconds/minutes/hours…} ago”)

Also there should be some review of all output types and type checks to avoid situations like these: Blockly handles comparison differently when taken from state directly or from intermediate variable · Issue #836 · openhab/openhab-webui · GitHub
(blocks refusing to assemble because of incompatible types)

How does Blockly handle Units of Measurement? That might actually be the highest priority to me given how often it shows up and how many problems it causes. Even if we don’t actually support the units themselves, we hopefully can at least make it work by calling .floatValue() on the states from Number Items.

The big problem is many bindings do not let you choose to use just a regular old number. You have to link the Channel to an Item with units.

Not too well I think. There could be a need for a “float value of” block.

Funny as this is my own issue and I am now in the position to fix it myself eventually :smiley:

Finally, after almost 2 weeks of trying to repair my OH production system and then finding the problem, I am back on track for blockly development… sigh…

Here is my latest design for the ephemeris blocks

with an example

generating

var ephemeris = Java.type("org.openhab.core.model.script.actions.Ephemeris");

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


if (ephemeris.isWeekend((0))) {
  logger.info('today is weekend');
}
if (!ephemeris.isWeekend((3))) {
  logger.info('today in 3 days is weekday');
} else {
  logger.info('today in 3 days is not a weekday');
}
if (ephemeris.isBankHoliday((0))) {
  logger.info('today is bank holiday');
}

@ysc Was it intentional that the today-block is black or should it have the OH color?

@rlkoshak Can you check if there is any other method we would need from here ? I don’t think so.

With that ephemeris is done. On to the next one.

@rlkoshak regarding

So the core actions (Actions | openHAB ) would be at the top of my list, perhaps even above Item metadata.

Which one would you like me to do first then?

  • edit: “real variable persistence via actions” is not possible
  • exec in /usr/bin/command
  • http call and ping
  • calling another script
2 Likes

posted openHAB specific block reference here
Let me know if pictures aren’t showing or some such :confounded:
and who can tell me how to make a post a wiki or just do so

Thank you, Andrew, for starting this :smiley:

The images come out fine so far.

I have several questions and recommendations

  1. Where would this page be located after the final write up? I would expect it to be near to Rules | openHAB but like https://www.openhab.org/docs/configuration/rules-blockly.html

I would therefore recommend to “write/design” it in that style.

  1. I wonder if it is possible to create subpages as I think the documentation could become pretty long. Unfortunately from it seems that this seems not possible? At least the menu to the left does not support it, does it?

  2. Can we move the documentation to github there and can collaboratively edit and review it?

  3. One of the added value of documentation is that it explains how to use something. With your notes I think you started doing that. Don’t get me wrong, I am happy you started it! :star_struck: What I love to see though is a comprehensive documentation eventually that allows openHAB users to quickly write rules without knowing too much about programming. So here’s my product vision for the blockly documentation pages :angel:

Therefore I would wish to read

  • what the block is meant for (and not only what it “does”). For example the things-block allows you to iterate over several blocks with a loop (see an example in this thread)
  • provide an example how it can be used (maybe not for each and any block but at areas where it is providing a more comprehensive understanding) - see this thread here for the many examples I have provided and I am sure we could do more
  • The blocks have tooltips that link (with sub-anchor) to the API-page that explains technical background, e.g. Ephemeris-Subsection. I would also add that link to the respective sections within your documentation.
  • Some of the blocks need setup to work. We should link to the respective pages within the openhab-doc-pages that explain the setup and it these are not yet comprehensive enough then also extend those. The reasoning behind that is that users who use blockly are probably not too technical and should find an easy to follow setup guide or at least a link to there, so they do not get frustrated to get it running quickly (for example voice tts).
  • I would love to have an introduction section about blockly on how to use them and link to respective official blockly pages that help the use get started even more quickly. That should also include some tips on how work with blockly (e.g. the code page) and how to “debug” it in case it doesn’t work as expected.
  • Maybe we can extend the pattern pages that Rick has provided over the years with examples how these can be done via blocklies now?

And having said that, of course I am happy to jump in and add to the documentation myself.

cheers
Stefan

good question Stefan
I remember Rich and Jerome having a discussion earlier in this thread about where the Blockly documentation would fit in and how it should be presented. I think that will have to be worked out. That is why I created a document here in the forum until such decisions can be made.

That is exactly right, I ‘started to do that’. Some of the blocks, I wasn’t sure exactly how they work and didn’t have time to try them out or look at the underlying code.
I agree with providing examples and links to more information ect. All great ideas

I figured, the say command for example requires a TTS service correct? That would need to be mentioned.

agreed

yes, yes agreed, if one of the mods can make the thread a wiki or tell me how to do so myself or move to git to work together is good with me.
The original doc is free to copy, modify or whatever

Initially no, but eventually ‘why not’ as it’s a new type dedicated to specify the day offset that thanks to a special output type, and the input check on the Ephemeris blocks, shouldn’t be useable outside the latter.

You may have noticed that I reverted the “item {}” and “thing {}” blocks under the openHAB category to the green-teal color that identiies text/strings (in the Text category), even if they’re not in the Text category themselves. IMHO this makes sense because these blocks only yield item names as Strings, only with a helpful UI, and can be manipulated with blocks from the Text category.

So if in the end we settle on an output type that represents date/time offsets, which could perhaps be used in both Ephemeris and persistence-based calculations, as discussed above, then we might choose a dedicated color for them and stick to it.

You may have noticed that I reverted the “item {}” and “thing {}” blocks under the openHAB category to the green-teal color that identifies text/strings

I actually hadn’t :slight_smile: so it is good you have just mentioned it.

The today-blocks are indeed already typed as

this.setOutput(true, ‘EphemerisDay’)

and it can only be applied to the Ephemeris-Check-Block.

Note that this is not a date-type because the API does not use a date but rather expects either today (=0) or “today+/-number” (=number). So the block is nothing different than the provided number in the end. We could have even completely left out the today-piece and just have the number but the idea you came up with with the today block looks much nicer, I think.

To be honest, I overlooked that there is a method to check the weekend by a date (see the third row)

isWeekend true if today is a weekend, false otherwise
isWeekend(<offset>) true if the day <offset> days from today is a weekend
isWeekend(<datetime>)

I used Date fields  |  Blockly  |  Google Developers as a new block type and now it is possible to also provide a date like so

Note that the date picker DOES NOT allow to the provide the date by variable containing a date! I can also not just allow a string because I need to know if a today or date field is provided to internally distinguish the read method to be used. They only way would be to provide a third date block that does not provide a date picker but would allow to provide a string instead directly. The issue with that though is that providing a date with the wrong format would result into an exception.

So, do we want to give the same greenish color or something else?

It looks really good. Thanks!

It’s of secondary priority but getBankHolidayName and daysUntil would be useful to a number of users.

Which ever use easiest I think. They are all pretty important though we will probably want to limit the http actions to just the simple cases.

I have to go back to

  • “real variable persistence via actions” - unfortunately I got it wrong. I thought this would be a method to persist values via openHAB but if course this is nothing but setting an item to a value and these methods allow the persistence functionality to be used to for example to retrieve an average or sum or lastValue…

So I would need someone who is willing to tell me what types of blocks we should really provide here and which not.

Ok, I’ll take care of getBankHolidayName and daysUntil at a later time.

Please recheck the above writing for ephemeris as I added a date option there.

I also added

Perfect! It’s looking really good and really useful. Thanks again for all the hard work!

1 Like

I’m not sure because that color denotes arbitrary Strings that can be manipulated - even if they are item names or thing UIDs - you can add suffixes, make substring replacements etc.

Ephemeris arguments I think are too specific to be considered arbitrary strings or numbers or dates, and the manipulation of these is probably not desirable. In the Voice & Multimedia category you have another example, the audio sinks and voices. While they are technically Strings the fact that they’re in another color entirely means the user should reuse them as-is and leave them be.

Note that you can update blocks based on e.g. the value chosen in a dropdown: see blockly/math.js at master · google/blockly · GitHub, the implementation of the blocks in the Math category. If you try the “0 is even” block and change the dropdown to “is divisible by” you’ll see that an input is appended to the block. Also in the “1 + 1” block you’ll see that the tooltip changes based on the chosen operation.

The file above has the implementation for those; it’s a little convoluted since they use mixins and mutators.

For reference in the Blockly repo (GitHub - google/blockly: The web-based visual programming editor.) you can find the block definitions of the standard blocks in blocks and the code generation in generators/javascript.

So do we want to take a different color like the sound gray one ?
image

for those who reading along the thread, this is what Yannick mentioned
image
image

Thanks for the hint - that is really interesting to know.
Now I remember that I have been reading something about that here where he explains how to do that.

Do you had a particular idea in mind where or in which case it would improve the new blocks or was it rather a general hint so I know (which I didn’t and appreciate to know now).

Thanks, it is about time I look closer into their blocks to learn from them. I am sure this could be a good treasure trove to get new ideas.

I had this idea to combine “today” and “today +/- x day(s)” into one, and eventually get rid of the block (just implement the conditional visibility into the final blocks), but it’s not mandatory.
As for the color, no strong opinion, as long as it’s significantly different than the other colors currently in use, I think the black is fine.

Next feature is working :smiley: as defined in Actions Subsystem

image

with the script in the script folder

image

being

logInfo(“helloScript”,“hello script”)

resulting into

2021-11-16 22:55:09.976 [INFO ] [penhab.core.model.script.helloScript] - hello script

Question: would there be any way to call a script as defined in the UI? Probably not

Calling “helloWorld” doesn’t find it as it really seems to look for a file.

Question: Does it make sense to support the transform function?

transform(String type, String function, String value)

If yes, can you provide an example that I could easily try out for testing

Question: This blockly feels a bit lonesome here :wink: Should we put it into some other category?

The other option we have is to add the

Regarding the exec function

  • Does it require the exec binding?
  • Do I have to allow the path for the exec binding to be allowed to accessed? (I think this was added for security reasons on M2 or so)

Yes but it’s just a regular rule so it would be like I posted up in post 103.

A “Script” in the UI is just a rule with a single script action tagged with “Script”. It’s actually a little confusing in that regard which, now that you’ve implemented it I wonder if this is going to cause some confusion.

Honestly the overloaded “Script” term is already causing confusion among users. Maybe if we change this action to “call script file” that might help. It makes it a bit more clear that we are calling a .script file, not a rule under the Script category in the UI.

As you found in your experiments, they are really two very different things.

Absolutely!

It’s going to be a little different based on which transformation you’re calling. For examples:

vat Transformation = Java.type("org.openhab.core.transform.actions.Transformation");
var map = Transformation.transform("MAP", "MyFile.map", "Some sting, maybe Item's state"); // Calls the map transformation
var regex = Transformation.transform("REGEX", ".*Begin(.*)End.*", "Some sting, maybe Item's state"); // Calls the REGEX transformation
var jsonpath = Transformation.transform("JSONPATH", "$.foo.bar", "Some JSON string with foo and bar elements, maybe Item's state");

It always takes three Strings, the first is the transformation to apply. The second is the argument to the transformation, such as the file to use or some other string telling the transformation what to look for. The last argument is the string that the transformation will transform.

It gets tricky because the first argument can only be one of the currently installed transformation add-ons. The second argument wholly depends on what the first argument is. So I’m not entirely certain if you can do much to help the user beyond just letting them entry arbitrary strings for the first two arguments. But if there were a way to provide just the list of installed transformation for the first argument and then a sort of builder for the second argument that would be fantastic, but I’m certain well beyond what’s possible.

I would expect “call rule” to go here as well. But in case I’d expect the category to become Scripts and Rules. I can also see executeCommandLine here too. I big gotcha with that one though is can you do a function with an arbitrary number of arguments?

Maybe to avoid confusion between executeCommandLine maybe we should name the block you’ve already built “call openhab script file” and then executeCommandLine can be something like “execute command line”.

An argument could be made that transform goes here too. In all these cases you are calling out to something outside of the current rule.

No, it’s a core Action available by default on all openHAB instances.

No, the whitelist doesn’t apply to executeCommandLine, for which I’m not super happy with as I think it too should be protected in the same way. Either the authorization built into OH 3 is sufficient for both the add-on and Action or it’s not. But I lost that argument.

So you are OK with calling executeCommandLine without any other external dependencies.

1 Like

I renamed the original block to “Call Script File”

Another good news. Even though I was worried about the complex code I got it working pretty fast (thanks to your perfect example) and I also support variables already.

This is how the blocks look like:

This is the code I create for Call-Script Block


var FrameworkUtil = Java.type('org.osgi.framework.FrameworkUtil');
var _bundle = FrameworkUtil.getBundle(scriptExtension.class);
var bundle_context = _bundle.getBundleContext()
var ruleManager_Ref = bundle_context.getServiceReference('org.openhab.core.automation.RuleManager');
var ruleManager = bundle_context.getService(ruleManager_Ref);
var map = new java.util.HashMap();

  map.clear();
  map.put('key','value');
  map.put('key2','value2');

ruleManager.runNow('helloWorld', true, map);

and the script name “helloWorld” is actually called. The code of the script looks like

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

logger.info('helloWorld was called')
logger.info('Param='+context.getAttribute('key'))
logger.info('Param='+context.getAttribute('key2'))

And it logs out

[INFO ] [org.openhab.rule.helloWorld         ] - helloWorld was called
[INFO ] [org.openhab.rule.helloWorld         ] - Param=value
[INFO ] [org.openhab.rule.helloWorld         ] - Param=value2

So this is a really cool block now.

  • Do you by chance now if this is synchronous call ? to me it appears it is
  • The question is also if we should support one block with and one block without params. Otherwise it would look like this (doing something like the gear icon of the if-else block from blockly is probably pretty tough for me at the moment)

image

Now on to the transform function… (I have to check the rest api to see if I can retrieve the transformation from the backend)