[ANNOUNCE] Visual programming a function node with Blockly - Feedback request

Julian (@TotallyInformation), just fyi. Seems you were right. Found by chance this article, where they sow this comparison:

So a bit like competitors ...
Bart

WE CAN!!! :slight_smile:

I've been playing with your code

image

@cymplecy: Aha, busted. My code is protected by international laws all over the world, and you changed it anyway ...

Well done!

P.S. was reading last night this article, and it seems that Google's Blockly team even went to kids at schools to test their UI. Just what we need :rofl:

1 Like

I'll think you'll find my mental age is appropriate to the task :slight_smile:

I like to think that I CAN think like a kid but many say I DO think like one :slight_smile:

2 Likes

Uh oh ... I'm in trouble again! :slight_smile:

Prepare yourself for even more hacking.....

image

So, as I've said before - I am a simple person :slight_smile:

So, here are my suggestions for some simple blocks that are similar to the standard change node but allow us to program in Blocky rather than having to use JSONata :slight_smile:

Then the existing Json objects category can be used for more advanced programmers

What do you think?

See that you are starting to enjoy Javascript coding, so perhaps you will not need Blockly anymore in the future :hugs:

Not much time, so some quick remarks:

  • The label '(node) context' seems ok to me, since it uses the naming convention of Node-RED and explains that is about node memory.
  • The 'msg' in the dropdown is indeed similar to the Change node, where there is only an input message. However in our blockly node you can build a NEW output message from scratch, or clone existing output messages... And users might wonder why those messages are not in the dropdown. Other ideas from other people?
  • The '.' notation is indeed another way to go. But not sure, because it could be that novice users don't understand the dots. But they would surely understand 'Get property X of object Y'.

Moreover I assume that users will also want to get nested properties, for example msg.payload.data. There are 4 different ways to solve that: see article. Anybody suggestions about that??'

Bart

1 Like

I'm just altering the text in your files :slight_smile:

I haven't written any JS code at all :slight_smile:

I was trying to get it as short as possible (so it could be horizontal) and the object.property nomenclature is the standard NR way but I think your right in that a bit of txt might be better (I just don't like having to use the word "object" as I think its frightening to non-expert Node-REDers)

I'll try out some variations

I didn't worry about msg.payload.data as I think that could still be handled in the Json objects category

My view is that the vast majority of people using Blockly would just want to manipulate the msg.payload object (and the context variables) so give them something easy to use at the top of 1st category e.g get/set/send

Fancy stuff like msg.payload.data etc could be handled by advanced blocks in the Json objects category using one of the nested properties approaches in that article

1 Like

Hi guys,

Back from holiday, so time to share a new version of the Blockly node on Github. I think that almost all feedback has been implemented, except from the timers (which will be postponed to version 0.0.2).

@cymplecy: I have restored the version back to 0.0.1. And be aware that all your local 'hacks' will be lost when you upgrade to the latest version!

All constructive feedback is welcome! Shoot ...

  • The Node-RED category is now in capitals:
    image

  • Since nobody was enthousiastic about a model like in OpenHab, I just added a new "on node closed" block to the Node-RED category. This allows users to execute some coding when the node is being stopped (e.g. at a deploy):
    image

    P.S. At least one message should arrive at the blockly node, otherwise the close-handler will not be registered (and not called) ā€¦

  • I added (in the 'Logic' category) a new "switch" block, based on an example I found in the Blockly forum (which I had to tweek a bit). In Simon's RGB colour example above, the hexdigit value check had to be repeated six time in the if-else-elseif statement. It seems to me that a switch block is a nice alternative to simplify this. An example:
    image

  • A new "return and send" block has been added (in the Node-RED category), with 'msg' as default input block:
    image
    Since there is no statement after a return, the block has no next statement gap (at the bottom)...

    Blockly doesn't offer such a block, since it is integrated in their 'function' block:
    image
    Since we are already inside a function (i.e. the on-input-msg-event-handler of our blockly node), we need to offer such a block ourselves ...

  • A default msg input block has been added (as shadow blocks) for the next 3 blocks:
    image

  • The 'node' memory label has been changed to '(node)context':
    image
    P.S. I haven't added the 'msg' option yet here (see Simon's approval above), since that seems to be someway not completely correct to me at the moment. I would love to have some extra feedback from others about this!

  • A new category "Buffer" has been added to the toolbox:
    image
    I implemented a small part of the NodeJs Buffer API, so users can at least handle buffer data (like images) in their blockly node. The following example shows (see new orange nodes) how it works:


    In the above example 3 buffer (variables) are created, data is being copied and the results are stored in the output message:
    image

    Some questions already about those Buffer blocks:

    1. The 'copy from buffer' block will generate a 'copy' statement, so I named it like that. Or should I call it 'clone from buffer' similar like the 'clone msg' block?
    2. Some blocks don't implement the full API. For example the 'buffer fill' block doesn't has a startIndex and endIndex input. Currently I fill the entire buffer for simplicity. Is that good enough?
1 Like

Hope you had a nice holiday and are all refreshed :slight_smile:

Re:Buffer category
I think we are missing a block to directly set the value of a buffer byte
For my Node-RED/Scratch interface I need to set the 4th byte to the length of the message and i used this approach in my original JS code

var msglength = msg.payload.length;
...
var outbuff = new Buffer(4 + msglength);

...
outbuff[3] = msglength;
...
return msg;

Thanks for this
I'm thinking that this block should just say return not return and send

Posted a new version on Github with following changes:

  • Added two blocks for getting and setting the value at a specified buffer index:
    image
    The problem is that the API is rather large, so I cannot add a block for every available function. Otherwise I end up building Blockly blocks for the remaining of my miserable life, which is not my intension. But you get those two for free, as a payment for your test services :wink:
    TODO: I have to add a type check, so you can only have an input value of 1 number or character. Don't know at the moment how to achieve that.
  • The return block has been updated:
    image
1 Like

Lovely :slight_smile:

So converted my Node-RED -> Scratch 1.4 message format function node to Blockly

image

Suggestion, as always :slight_smile: , either default byte index to 0 or use Blockly 1-based and get your code to convert the 1 to a 0 for the JS

Obviously pros and cons of using 0 or 1 based indexing.

If I was voting, I'd use standard 1-based indexing in Blockly (as everything else in Blockly is 1-based and I'm a Scratcher and everything is 1-based in that as well) and do the conversion to JS 0-based in your code

Simon,
Think we can call you 'mister Blockly' from now on, because I wasn't even aware that Blockly is 1-based instead of 0-based...

Found this discussion on the Blockly forum:

Traditionally Blockly uses one-based indexing for strings and lists. This is generally a good choice for beginner programmers, since most people start counting at one. However, there have been periodic calls for Blockly to use zero-based indexing to support more advanced programmers.
Monica has just checked in a significant update to the standard text and lists blocks that allows developers to choose the indexing type. If you want to switch to zero-based indexing set these two properties in your code:
Blockly.Blocks.ONE_BASED_INDEXING = true;
Blockly.JavaScript.ONE_BASED_INDEXING = true

I could take those properties into account in my two Buffer blocks. But that is only useful if the user can set those properties to true/false. Does anybody think it might be useful to add such behaviour to the node's config screen:

image

Or do we hypothesize that more experienced users won't use Blockly anyway (since they just put Javascript code in the function node). In that case we can skip this part of the discussion ...

Well it definitely needs a note in the Info panel on the right to say that Blockly by default indexes from 1....

I think having a checkbox that lets users switch is a very good way around the problem

I'd change the text to (default) instead of (recommended) so as to stop any wars breaking out :slight_smile:

And if users leave it checked, then your Blockly buffer code would need to work behind the scenes to convert get byte at index 1 of myBuffer to myBuffer[0] (and same for set byte)

1 Like

I'd be wary of having checkboxes for options that your target user won't understand the meaning of. It may be one checkbox now, but the temptation is then there to add other options.

I would suggest stick with 1-based indexing, with a note in the info at first. Only add a checkbox if it proves to be a real problem.

1 Like

[Big Push] :slight_smile:
(Coming from point of view of a Node-REDer who's just used standard nodes and contrib nodes and is wanting to make their own function node and knows little/nothing about Javascript/JSONata but understands Node-RED logic and flows)

Standard Node-RED way of setting the msg payload is to use

image

So I think Blockly should provide simple blocks looking like this

image

(I've got rid of dropdown from previous suggestion so that 1st parameter can now be any object and changed the . to property

I think its important to stick with the standard NodeRED order of object followed by property

(Luckily, that is the order the JS code uses so I think that's 2 votes in favour :slight_smile: )

msg['payload'];

flow.set('limit', 999);

Simon

1 Like

Ok will try to summarize your proposal here, so others can join the discussion without having to dig through the entire history. You want to combine both get-blocks (i.e. get from Object and get from Node-Red memory) into a single get-block, and combine the two set-blocks into a single set-block. To get that done, you introduce new 'global', 'flow' and '(node)context' blocks:

image

I agree that it looks a bit more similar to the standard Node-Red nodes, and perhaps less confusing if a user has a single get and set block. Some remarks:

  • The 'property' and 'value' fields have become inline fields (similar to my first version), which means it will be fixed: e.g. when you set it to 'payload', you cannot change that value afterwards. I assume you have done that because you like to have it as a horizontal block of a single line. I would like to keep those fields external, so you can change these values dynamically.

    image

  • About the inline field, that can contain any Javascript object. Was first thinking that your new blocks (e.g. 'flow') needed to return an 'Object', otherwise you cannot use them in the inline field to get/set it. However then users could use your new blocks everywhere, where an Object is required. For example:

    image

    That would make no sense at all. Therefore I'm going to introduce a new Blockly type 'Memory' (similar to my new 'Buffer' type), beside the existing Blockly types like 'String', 'Number', 'Object'... Then I allow both 'Object' OR 'Memory' types in my set/get blocks. But I will have to check that users cannot use these 3 blocks in any other blocks from Google (that have NO type checking to allow every kind of input) !!

  • Is this more self explaining?
    image

So I think it is possible what you ask, but what do others think about your proposal?

I haven't noticed any difference in how fields can be used between inline modes and external mode. I prefer the look of inline mode but that's all :slight_smile:

I realise that trying to allow msg/flow/global/context blocks to be used interchangeably could lead to wrong block in wrong slot but thought that the benefit out-weighed the possible errors.

Maybe a compromise is to just check in the Node-RED category blocks as most possible errors would happen there?

Or maybe revert back to the earlier dropdown msg/flow/global/context to avoid a lot of work? There would still be the Json category blocks to deal with get/setting other objects apart from msg

Morning Simon,

That could be the start of yet another discussion...
The same input can be inline or external. For example:
image

Google's design guideline: Use inline inputs when a block is likely to have small inputs such as numbers.
So in our case the input is a property name (i.e. "payload"), so it is indeed making sense to use an internal input:
image

But when you want to compose the property name dynamically (e.g. to loop over message properties), it doesn't look nice anymore since the block becomes very large. For example:
image

So we have a number of options to vote for:

  • we use inline inputs since most of the time the values will have a short fixed value.
  • we use external inputs for cases where the value needs to be generated by N other blocks
  • There is also a third option: seems you have a context menu available (at right click) where you can expand all blocks. This way the inline inputs automatically become external. But I have posted an issue on the Blockly forum, since that doesn't seem to work correctly.

That still bothers me, because we need to respect the type checking!
For example the get/set blocks don't do type checking on the value input, since users should be able to store ALL values on the Node-Red memory. But that means that they can even do this:
image

Storing flow on flow memory makes no sense. So I don't think it is a good idea to have your 3 new blocks (flow/node/global) available in the toolbox....