Extending Blockly with new openHAB commands

A very good point, I’ll check if zdt-states can be easily compared to each easily. This of course must be the case.

This really does pose the question of what is “built-in material” and what should be delegated to block libraries (with the “out-of-band” possibilities they offer).

To me it deals with both subject domain and complexity of the subject matter.

For instance, I wouldn’t support blocks that do administrative operations - like alter items or things - in the built-in library, because I believe rules in essence are for acting on items, or eventually things (through things actions), but not modifying the configuration.
But if you do want to modify the configuration with Blockly scripts, then you can, but you should install this “admin” block library which will allow you to do that.

On the other hand, while date & time manipulation is desired in rules in general, it is such a complex subject matter that we could perhaps have “go-to” block libraries in the marketplace (the brilliant Date and Time is proof that we can solve such problems with block libraries) for those subject matters. It comes from the observation that we would struggle to get it exhaustively “right” no matter the effort, and libraries would allow a more organic progress.

This is interesting, but I’d say we’ll have to get stable links to reference docs before we do that.
“Stable” docs can be in this forum too but it has to be clarified.

We have a primitive system of “canonical URLs” which is used in some places around the UI - for instance when you click the “Learn more about profiles” link:

See for instance Items | openHAB

This allows to change them if the docs get reorganized without modifying the UI code.

I’m not sure the complexity of the problem should be the deciding factor.

In my mind, if it’s something that most average user is going to need to at some point it should probably go into the core. Testing whether now+X seconds is before/after the state of a DateTime Item is a pretty common task in all sorts of rules. Something so fundamental feels like it should be in the core.

I don’t think that the core blocks need to exhaustively cover every single possible date time operation. But I would expect it to cover maybe the top five or so most common ones. In my experience, comparing now to a DateTimeType is way more common of an operation than most any other date time operation short of comparing a variable saved last time the rule ran to now.

But instead of a core or Marketplace decision maybe it’s more appropriate to set up some sort of Marketplace to core pipeline. The Marketplace posting looks pretty complete and functional. How challenging would it be to migrate that into core (with @deibich’s permission and hopefully participation of course)?

1 Like

If you both feel that this is a better approach, then I’ll stop mine and I am sure, Yannick could migrate that one into the core blocks.

I agree.

Not sure if you saw it but I am currently in the process of moving the blockly reference to openhab docs (I am already discussing a few things with @Confectrician how to do it best). I have already forked the repo and moved over the intro and some minor parts. It will take another few (hopefully not too many) weeks though, until I have done that as I am also refining the images, so everything looks very pretty.
The final blockly-docs link is the one that I would then want to put the toolbox only when I am done with that, e.g.

 /link/blocklib    /docs/configuration/rules-blockly-main.html

So, I am on it.

Would be nice to see more blocks for date and time in core. Please feel free to use the blocks as you like.

Actually not too hard, the logic to translate block libraries into actual block categories is already there. It does not have the same level of complexity as actual code, and the performance is probably subpar, but it could work still. Same for widgets, we could have additional sources for widgets than what the user creates or imports from the marketplace in Developer Tools > Widgets.
The question is where we make the split between built-in blocks defined in actual JS, built-in block libraries, and “ad-hoc” imported libraries. I don’t have a definitive answer.

I don’t know where the divider is either. But I do firmly believe that at least the most common time operations should be core blocks. We don’t necessarily need to cover them all, but being able to compare the state of a DateTime Item with now plus or minus some time delta would be among those. Being able to post update a date time derived from now plus or minus some time delta would also be among those.

I can see everything else like Duration operations and stuff like that being left to a library or the inline script block.

I’ve not used Blockly enough yet to discover any other major missing piece but I don’t think there are any after this. I suspect anything else will be mostly focused on dealing with refinements like Units of Measurement and stuff like that.

I agree, the datetime blocks are really important I would definitely vote for adding them to the core. At least in my rules I often use it and the datetime block we should also do is a way to add to dates and times similar what I had in mind (adding or subtracting something in one block because otherwise I think it becomes pretty quickly confusing and convoluted)

Hi Yannick,

is there a way to build the openhab-docs locally, so I can check how my my writing would look like before I commit and push it.

I looked at your block post about vuepress and also the ruby files in the repo but I wasn’'t sure what has to be run (I checked the README, the files in .vuepress and also tried to figure out the build process online but couldn’t). Sorry if overlooked something.

UPDATE (SOLVED):

  • I installed vuepress via npm install vuepress
  • I then ran npm run build-preview

It runs fine and creates all the files in the vuepress folder.

There is a downside with that method though because as it runs “ruby prepare-docs.rb --delete-sources” it deletes a lot of files in the git repos which appears to become lots of deleted file. The alternative would be to do the following two step individually

  • npm run prepare-docs
  • npm run build-only

which doesn’t delete the files and does render the html but in the end ends with an error like

error Error rendering /addons/actions.html: false
undefined
error Error rendering /addons/bindings.html: false
undefined
error Error rendering /addons/io.html: false
undefined
error Error rendering /addons/transformations.html: false
undefined
error Error rendering /addons/persistence.html: false
undefined
error Error rendering /addons/voices.html: false
undefined
TypeError: Cannot read property 'label' of undefined
    at Proxy.render (addons/actions.md?547e:1:72156)
    at VueComponent.Vue._render (/Users/xxxx.xxxx/Development/checkout/openhab-docs/node_modules/vue/dist/vue.runtime.common.dev.js:3559:22)
    at resolve (/Users/xxxx.xxxx/Development/checkout/openhab-docs/node_modules/vue-server-renderer/build.dev.js:8444:27)
    at waitForServerPrefetch (/Users/xxxx.xxxx/Development/checkout/openhab-docs/node_modules/vue-server-renderer/build.dev.js:8316:3)
    at renderComponentInner (/Users/xxxx.xxxx/Development/checkout/openhab-docs/node_modules/vue-server-renderer/build.dev.js:8455:3)
    at renderComponent (/Users/xxxx.xxxx/Development/checkout/openhab-docs/node_modules/vue-server-renderer/build.dev.js:8412:5)
    at renderNode (/Users/xxxx.xxxx/Development/checkout/openhab-docs/node_modules/vue-server-renderer/build.dev.js:8323:5)
    at resolve (/Users/xxxx.xxxx/Development/checkout/openhab-docs/node_modules/vue-server-renderer/build.dev.js:8450:5)
    at waitForServerPrefetch (/Users/xxxx.xxxx/Development/checkout/openhab-docs/node_modules/vue-server-renderer/build.dev.js:8316:3)
    at renderComponentInner (/Users/xxxx.xxxx/Development/checkout/openhab-docs/node_modules/vue-server-renderer/build.dev.js:8455:3)
    at renderComponent (/Users/xxxx.xxxx/Development/checkout/openhab-docs/node_modules/vue-server-renderer/build.dev.js:8412:5)
    at RenderContext.renderNode (/Users/xxxx.xxxx/Development/checkout/openhab-docs/node_modules/vue-server-renderer/build.dev.js:8323:5)
    at RenderContext.next (/Users/xxxx.xxxx/Development/checkout/openhab-docs/node_modules/vue-server-renderer/build.dev.js:2611:23)
    at cachedWrite (/Users/xxxx.xxxx/Development/checkout/openhab-docs/node_modules/vue-server-renderer/build.dev.js:2464:9)
    at renderStringNode$1 (/Users/xxxx.xxxx/Development/checkout/openhab-docs/node_modules/vue-server-renderer/build.dev.js:8530:5)
    at RenderContext.renderNode (/Users/xxxx.xxxx/Development/checkout/openhab-docs/node_modules/vue-server-renderer/build.dev.js:8321:5)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! openhab-docs@3.0.0 build-only: `vuepress build .`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the openhab-docs@3.0.0 build-only script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:

Can you explain that?

Wouldn’t it be a good idea to add that to the README.md?

Building the docs is a mess, yes. And it’s not well documented.

I wouldn’t even try to build them locally, just create a PR and you’ll get a preview built for you.
It’s updated every time you push new commits.

1 Like

Just wanted to say thanks for the work done on Blockly! I managed to migrate a number of old rules in jython easily to Blockly with only very limited programming knowledge. Very pleased with the result!

I was wondering if Blockly would ever support reading item metadata? That would allow for more flexibility in my rules. Or could I use the inline script option for that for now? In case of the latter would somebody have an example that reads item metadata in an inline script I can study?

Thanks, I appreciate it.

What exactly are you missing besides these?

So basically a way to access (read) custom metadata namespaces from the item.

For example; I would like to define for a dimmer light item a default delay (how many seconds) before it is turned off again when the light is triggered by a motion sensor. Or the actual brightness for a given time of day.

With the old jython rule I used each light item had meta data like this (in a custom namespace):


value: ""
config:
  light_action:
    active:
      modes:
        DAY:
          low_lux:
            brightness: 98
          lux_trigger: 0
        EVENING:
          low_lux:
            brightness: 98
          lux_trigger: 0
        MORNING:
          low_lux:
            brightness: 75
          lux_trigger: 0
        NIGHT:
          low_lux:
            brightness: 5
          lux_trigger: 0
        PARTY:
          low_lux:
            brightness: 98
          lux_trigger: 0
    inactive:
      delay: 180
    lux_item_name: LocalSun_DiffuseRadiation

I’m probably going to simplify this configuration but I guess it’s a good example. I could then create very generic Blockly rules that take the meta data as input for specific actions.

But perhaps it’s not really part of the standard Blockly journey and requires actual programming. I don’t know what the consensus is what should or should not be part of Blockly…

Metadata gets a little complicated in Blockly because it’s not just a name/value pair but name/value/array of more name/values. Sometimes you just need the value, other times you just need the array of name/values, sometimes you need both.

You could use the inline script for this I think. But it’s awkward. First you need to get the MetadataRegistry and some other classes you’ll need.

    var FrameworkUtil = Java.type("org.osgi.framework.FrameworkUtil");
    var _bundle = FrameworkUtil.getBundle(scriptExtension.class);
    var bundle_context = _bundle.getBundleContext()
    var MetadataRegistry_Ref = bundle_context.getServiceReference("org.openhab.core.items.MetadataRegistry");
    var MetadataRegistry = bundle_context.getService(MetadataRegistry_Ref);
    var MetadataKey = Java.type("org.openhab.core.items.MetadataKey");

Only then can you query for metadata on an Item:

var metadata = MetadataRegistry.get(new MetadataKey(namespace, itemName));
var value = metadata.getValue();
var config = metadata.getConfiguration();
var myEle = config.get('myElement');

In JS Scripting it’s much easier.

var value = items.getItem(item).getMetadataValue(namespace);

Thanks! I’ll try the inline script option first. One of these days I need to start with JS Scripting!

Just to let you know, David, I have started working on bringing these over to the core. It will probably take some time until I have done everything because I need to make sure it is all (backward) compatible and working well with the current blocks. Eventually when I do the Pull-Request to have these merged I will attribute it as contribution from you.

The first two are already working

As you can see I intentionally use input fields which is a bit less compact but allows to use computed values as well.

1 Like

Thank you for letting me know.

I think it’s good how you did it, since variables can also be used in this way. Due to the lack of custom validators I used number_field for the input. They allowed me to restrict the user’s input, but that may not be necessary.