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


#125

Simon,

A new version is available on Github to fit your needs:

  • Your pull request has been merged, so the orange color (in the color picker) is changed to yellow:
    image

  • The status node has now a default empty text field (instead of no text field):
    image

  • I have added a new 'remove node status' block:

  • The bug about the non-existing output number is fixed. Problem was that I choosed at generation time which code I had to generate: the code with msg.send ... OR the code with node.error ... But that was incorrect in your case: you used a variable (which can change at runtime), so at generation time I cannot always determine which port number will be used.

    So in the new version I had to generate code with BOTH msg.send ... AND the code with node.error ... At runtime one of both code snippets will be executed, depending of the output number being passed at that moment. So I tried to generate something like this:
    image
    However the code at line 1 is not readable for users that want to learn Javascript this way, due to the magic numbers (first '1' is the outputNumber and second '1' is total available number of outputs). Tried to solve this by generating automatically variables:

    const OUTPUT_NUMBER = 1;
    const AVAILABLE_OUTPUTS = 1;
    if ( OUTPUT_NUMBER > AVAILABLE_OUTPUTS) {
       ...
    

    However this doesn't work if you use multiple send blocks in your editor, since you will end up with duplicate variables. That can be solved by generating unique variable names, but then it becomes messy ...

    To get around this, I now generate a function at the top (which is used further on) :
    image

    I THINK THIS WAY THE MAGIC NUMBERS ARE EXPLAINED ENOUGH. IS THIS A GOOD SOLUTION OR SHOULD I SOLVE IT ANOTHER WAY ???

    P.S. if multiple send blocks are available in the editor, only 1 function will be generated and used by all those blocks...


#126

re Bug above
That's been fixed :slight_smile:
But still not quite right

image

var outputPort;

function isValidOutput(outputNumber) {
  const AVAILABLE_OUTPUTS = 2;
  if (outputNumber > AVAILABLE_OUTPUTS) {
    node.error("Cannot send to output outputPort, since only 2 outputs available");
    return false;
  }
  else {
    return true;
  }
}


outputPort = 1;
if ((msg['payload']) == true) {
  outputPort = 2;
}
if(isValidOutput(outputPort)) {
  node.send([ null, null ]);
} 

I think it should end up issuing something like
node.send([null,msg]);


#127

I must have pressed button at same time as you

Let me read yours 1st :slight_smile:


#128

mm...I see its complicated :frowning:

If you can't see how to make it work at the moment then maybe remove ability to have more than 1 output at the moment.

Add it back in a later release?


#129

I'm currently using this as a workaround for the moment

image

var outputPort;

function isValidOutput(outputNumber) {
  const AVAILABLE_OUTPUTS = 2;
  if (outputNumber > AVAILABLE_OUTPUTS) {
    node.error("Cannot send to output 1, since only 2 outputs available");
    return false;
  }
  else {
    return true;
  }
}


outputPort = 1;
if ((msg['payload']) == true) {
  outputPort = 2;
}
if (outputPort == 1) {
  if(isValidOutput(1)) {
    node.send([ msg, null ]);
  }
} else {
  if(isValidOutput(2)) {
    node.send([ null, msg ]);
  }
}

which is good enough for me at moment :slight_smile:
Simon


#130

Damn again... I have currently a loop inside the code generator, to build the node.send statement:

    // Send the message only to the specified output number, and null to all other outputs.
    var outputArray = '';
    for (var i = 1; i <= Blockly.nodeOutputs; i++) {
        if (i > 1) {
            outputArray += `, `;
        }
        
        if (i == outputNumber) {
            outputArray += `${inputValue}`;
        }
        else {
            outputArray += `null`;
        }
    }
    
    var code = `if(${functionName}(${outputNumber})) {\n`;
    code +=    `  node.send([ ${outputArray} ]);\n`;
    code +=    `}\n`;

But since I don't know anymore at code-generation-time which output number will be used (since that is only determined at run-time), this means I have to put the above loop also in the generated Javascript. This will result in unreadable code. Don't like that. It should stay in the code generator, and be invisible to the users.

Isn't it better that we don't allow the output number to be generated at runtime. I.e. only allow a fixed number to be entered. The logic to determine which output needs to be used shouldn't be INSIDE the output_number input field, but instead AROUND our send-block. For example by using an if-block:

image

Otherwise nobody will understand the generated code anymore. Does this makes sense?
@TotallyInformation: Julian, would be nice to get your opinion. And also other users ...


#131

Now I saw your latest post too late. Seems my last proposal is the same as your workaround ...


#132

I reworked the send block to work again with fixed output numbers.

In the following example I have a blockly node with 3 outputs.

  • Messages with payload '1' will be send to output 1
  • Messages with payload '2' will be send to output 2
  • Messages with payload '3' will be send to output 3
  • Messages with payload '4' will result in an error

I think this enough for most users. It generates very compact understandable Javascript code, and the users are still able to do some more advanced stuff (like the message routing in the above animation).

P.S. If no counter proposal, I will put this version on Github tomorrow evening.


#133

My counter proposal is to allow arrays to be sent instead of just msg

so have a block
send xxx to output
where xxx defaults to msg

but let people set xxx to [msg,null]
or whatever they want

This would align it perfectly with JS


#134

Since there are e.g. multiple LOOP blocks available, we might offer two separate SEND blocks:

  • one with an msg and an output number
  • one with a msg array

#135

Not sure what you mean by "Since there are e.g. multiple LOOP blocks available,"

I'm off out now till 16:00 GMT - see you later :slight_smile:


#136

I just wanted to say that Google also provides sometimes multiple blocks to achieve the same result. For example when you want to repeat something 10 times, they offer two blocks to do this:
image

So we can also offer two separate blocks for sending messages: one that accepts a list and another that accepts an output number. That's all ...


#137

understood


#138

Sorry been busy catching up work.

In regard to having multiple output channels, the Node-RED way is to define the number in the configuration of the node instance. This makes it fixed and therefore known in advance doesn't it? Or have I missed something? Maybe someone could drop in an example flow to illustrate the issue?

In regard to having multiple blocks to do something similar, I think this is absolutely in line with the expected audiences. Having a simplified block and one that is more complex but flexible. As long as it doesn't get out of hand so that you end up with thousands :smirk:

One small thing about code style - you seem to have a lot of back-ticks rather than the single quotes (or double if including escaped control characters) I would generally use - is there a reason for that? I'm not sure if there is a performance or other impact from only using back-ticks?


#139

The "problem" is that , at present moment, the Blockly node lets me use a variable for the ouput.
But since the value of the variable is not known at "compile time" (when the JS is generated) then trying to cope with that situation leads to a lot of complex JS (that Bart is trying to avoid)

(Follow the links to previous posts - forum doesn't format them properly when I pasted the link in!)


#140

But can't you simply fix the number of outputs in advance like you would have to in a function node?

Sorry if I'm being thick, it's been a long week and I spent the whole afternoon in a remote workshop designing a data model - brain melt!


#141

Yes AND No - think Schrodinger's Cat Problem :slight_smile:

The issue is not for those suffering from withered brain cells :slight_smile:


#142

Hmm, thought so (background sound of scotch being poured, glugging sound and deep sigh of contentment!)


#143

I'm thinking this issue may take up a lot of time to get right

So I propose just scrapping option of using multiple outputs for the moment and re-introduce them later

In the meantime, if an advanced users wants multiple outputs, then could simply set a flow context (say called whichOutput) and use a switch node following the Blockly node to do the actual switching dependant on value of flow.whichOutput

image

image


#144

Hi Julian (@TotallyInformation),

I'm back at home, after consuming some lovely Belgian beers. So don't believe everything I'm saying at the moment :roll_eyes:

Will try to explain the issue, like I always explain such things to an audience suffering from melted brains...

  • Below the Blockly editor you can define the number of output ports (similar to a function node):

    image

    This number is available when the Javascript is generated (when the 'Done' button is pushed). So far so good ...

  • In the send-block you can specify to which of those available outputs you want to send the message. In the first version this was a numeric input field:

    image

    This output number was also available when the code was generated (at the 'Done' button). So the generator had both numbers, and could do it like this:

    IF outputnumber > availableOutputCount THEN GENERATE 'node.error(...)'
    ELSE GENERATE 'node.send([ null, null, msg, null ])' --> the code generator composes the array !!

    So everything was working fine. In both cases only a single line of Javascript code was generated. Clean and easy to understand for somebody that wants to learn Javascript from the generated code ...

  • However in a later version I changed the numeric input field by a an input that allows any block that returns a number. For example:

    image

    The outputPort variable is set to 2, so the msg is being send to port 2 (since ouputPort variable contains 2). This allows us more flexibility, since users can now calculate an output number dynamically via other blocks. That sound good, but now I have a PROBLEM: when the code is generated (at 'Done' button), the generator only knows the number of available output ports. But the code generator doesn't know the output port number, since the variable outputPort is only calculated at runtime. So the code generator cannot generate the array [ null, null, msg, null ]. So that array needs to be generated at runtime, which means that the Javascript code to compose that array also needs to be put in the generated Javascript! This means the generated code will become very complex and difficult to understand !!!!

This is not what I want, so I want to get back to the first version (with the numeric input field). That works fine and the user can also do some advanced stuff with it.

Now it is your turn to give an example of what you mean ...

I think that the version (with a numeric input field) is very usable, so we should introduce it already in the first release of the blockly node. In the second release (together with timer support) we could add another EXTRA send-block, e.g. based on your array.

Keep in mind that I have already spend more than 6 weeks al my free evenings to this node. And my holiday ends this weekend, so from next week I will have even less time available. And I have still a lot of other Node-RED related stuff on my todo list, so I cannot postpone to much blockly stuff to the next release. Hope you can understand that.