Skip to content

Custom nodes

Klervi edited this page Jul 22, 2019 · 5 revisions


Install new nodes

The palette catalog

//

Other nodes

//

Build your first node

Node-RED documentation

[Nodes] consist of a pair of files; a JavaScript file that defines what the node does, and an html file that defines the node’s properties, edit dialog and help text.

→ Read Node-RED documentation to learn how to create nodes.
This Wiki does not give you the basics.

Nodes location

Your own nodes must be located in the "node-red-contrib" folder of your bot. Each node should be accompanied by a package.json file in order to be loaded in your Node-RED environment.

QRCode node example

The QRCode node is available here.

The HTML file

→ Learn the basics first.
The HTML file consists of 3 main parts: the node's properties, the node's display and the node's informations.

1. The node's properties :

<script type="text/javascript">
    RED.nodes.registerType('qrDecode', {
        category: 'VISEO_HELPER',
        color: '#3FADB5',
        defaults: {
            name:     { value: undefined },
            input:    { value: undefined },
            output:   { value: undefined },
            pptTypeIn:  { value:"msg"  },
            pptTypeOut: { value:"msg"  },
        },
        inputs: 1,
        outputs: 1,
        icon: 'qr-code.svg',
        align: 'left',
        paletteLabel: 'QRDecode',
        label: function () { return this.name || 'QRDecode' },
        oneditprepare: function() {
            $("#node-input-input") .typedInput({ default: this.pptTypeIn  || 'msg', types:['msg']});
            $("#node-input-output").typedInput({ default: this.pptTypeout || 'msg', types:['msg']});
        }
    });
</script>

The RED.nodes.registerType function required the node's type and its definition:

  • category, color, icon, align and paletteLabel refer to the node's display on the Node-RED palette.
  • defaults refers to the node editable properties. They are often needed by the JS file.
  • inputs and outputs are set at 1 here; we don't need several outputs.
  • oneditprepare function is called when the edit dialog is being built. Here, it is used to set the editable input types.

2. The node's display :

<script type="text/x-red" data-template-name="qrDecode">
    <div class="form-row">
        <label for="node-input-name"><i class="icon-tag"></i> Name</label>
        <input type="text" id="node-input-name" placeholder="QRDecode">
    </div>
    <div class="form-row">
        <label for="node-input-input"><i class="icon-tag"></i> Input</label>
        <input type="text" id="node-input-input" style="width: 70%" placeholder="prompt.attachments[0].contentUrl"/>  
    </div>
    <div class="form-row">
        <label for="node-input-output"><i class="icon-tag"></i> Output</label>
        <input type="text" id="node-input-output" style="width: 70%" placeholder="payload"/>  
    </div>
</script>

Each editable input is linked to a HTML element, except the types here (pptTypeIn and pptTypeOut).
If the input's name is "myowninput" in the defaults section, the id of the input section should be "node-input-myowninput". Otherwise, the input will not be registered.
The <i class="icon-tag"> refers to the icon displayed next to the label.

3. The node's informations :

<script type="text/x-red" data-help-name="qrDecode">
</script>

Here, there isn't any help text to be displayed on Node-RED.

The JS file

→ Learn the basics first.
→ The complete JS file is available here.
The JS file consists of a main function, module.exports, and the node's behavior functions.

module.exports = function(RED) {
  const register = function(config) {
    RED.nodes.createNode(this, config);
    let node = this;
    
    start(RED, node, config);
    this.on('input', (data)  => { input(node, data, config) });
    this.on('close', (done)  => { stop(done) });
  }
  RED.nodes.registerType("qrDecode", register, {});
}

The first thing to do in the JS file is to create the node with the RED.nodes.createNode function. This is usually done in the register function.
All the editable inputs defined in the HTML file can be found in the config object.

Here, we defined two main methods in our code: input and stop.

const stop  = (done) => { done(); }
const start = (RED, node, config) => { }
const input = (node, data, config) => {

  let value = helper.getByString(data, config.input || 'prompt.attachments[0].contentUrl');

  // 3. End the node
  let done  = (err, json) => {
    if (err) return node.warn('Decode Error: '+err);
    helper.setByString(data, config.output || 'payload', json);
    node.send(data);
  }

  // 1. Buffer decode it
  if (value instanceof Buffer){
    return decodeBuffer(value, done);
  }

  // 2. URL download Image
  if (typeof value === 'string' && value.indexOf('http') === 0){
    request({ url: value, method: 'GET', encoding : null }, (err, res) => {
        if (err) { return node.warn('HTTP Error: ' + err); }
        decodeBuffer(res.body, done);
    });
  }
}

The input method uses the editable inputs (config.input and config.output) and decribes the node's behavior.
In this node, we only have 1 output. A call to node.send(data) sends the message to the output. A call to node.error(err) sends an error to Node-RED and stops the flow, while a call to node.warn(err) will not stop the flow.

The JSON file

{
    "name"          : "node-red-contrib-viseo-qrcode",
    "version"       : "0.0.1",
    "description"   : "Decodes a given QrCode",
    "dependencies"  : {
        "jsqr": "^0.2.2",
        "jimp": "^0.2.27",
        "request": "^2.81.0",
        "query-string": "^5.0.0",
        "node-red-viseo-helper" : "~0.1"
    },
    "repository" : {
        "type":"git",
        "url":""
    },
    "license": "Apache-2.0",
    "keywords": [ "viseo", "sarah", "node-red" ],
    "node-red" : {
        "nodes": {
            "qrcode": "node-qrcode.js"
        }
    }
}

For several nodes in the folder, we should add them to the 'nodes' section.

Naming and Scope

  • All packages should be named node-red-contrib-viseo-* to scope and find libraries.
  • Packages should define a big features (like a MongoDB Node) or set of REST Services (like Microsoft Cognitive Services)

The implementation between Microsoft Computer Vision and Microsoft LUIS is really close whereas Google Computer vision is far from Microsoft implementation. So node-red-contrib-viseo-microsoft and node-red-contrib-viseo-google is better than node-red-contrib-viseo-computervision

Input / Ouputs

Nodes properties should be dynamic and set/get the data from the flow. Node Helper library provides setByString() and getByString() function to work with deep data.

  let property = helper.getByString(data, 'path.to[3].property', 'default')

Node Message from BotBuilder package has improved features (see marshall()) :

  • search/replace all message {with.properties} text using helper.resolve()
  • translate all properties in curent bot language
  • use Mustache some {{{mustach code}}} here

Getting Started