【NodeRed】客製化開發

474 阅读7分钟

1. Develop Tool

  • Nodejs
  • Git

2. Code

  • 拉代碼

    git clone https://github.com/node-red/node-red.git

  • 啟動

    cd node-red

    npm install

    npm run build

    npm start

  • 訪問服務

    http://127.0.0.1:1880

3. Develop

nodered.org/docs/creati…

image.png

3.1 Create File

序号 文件 说明
1 package.json package.json文件是一个标准的用于描述NodeJs模块的文件,用于将其打包为一个npm模块
2 lower-case.js 用于定义节点的功能
3 lower-case.html 用于定义节点的属性、编辑对话窗口和帮助内容

image.png

3.1.1 package.json

  • 進入開發的node目錄下面,我的叫demo
cd xxxx/NODE-RED/packages/node_modules/@node-red/nodes/core/demo
npm init
  • 如果開發多個節點
{
    "name" : "node-red-contrib-example-lower-case",
    ...
    "node-red" : {
        "nodes": {
            "lower-case": "lower-case.js""demo": "demo.js"
        }
    }
}

3.1.2 lower-case.js

module.exports = function(RED) {
    function LowerCaseNode(config) {
        RED.nodes.createNode(this,config);
        var node = this;
        node.on('input', function(msg) {
            msg.payload = msg.payload.toLowerCase();
            node.send(msg);
        });
    }
    RED.nodes.registerType("lower-case",LowerCaseNode);
}

3.1.3 lower-case.html

<script type="text/javascript">
    RED.nodes.registerType('lower-case',{
        category: 'function',
        color: '#a6bbcf',
        defaults: {
            name: {value:""}
        },
        inputs: 1,
        outputs: 1,
        icon: "file.svg",
        label: function() {
            return this.name||"lower-case";
        }
    });
</script>

<script type="text/html" data-template-name="lower-case">
    <div class="form-row">
        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
        <input type="text" id="node-input-name" placeholder="Name">
    </div>
</script>

<script type="text/html" data-help-name="lower-case">
    <p>A simple node that converts the message payloads into all lower-case characters</p>
</script>

3.1.4 Install && run

1.安裝node
  npm install E:\xxxx\NodeRed\node-red\packages\node_modules\@node-red\nodes\core\demo

2.啟動
  npm run dev

3.2 Document

3.2.1 Status

image.png

this.status({fill:"red",shape:"ring",text:"disconnected"});

this.status({fill:"green",shape:"dot",text:"connected"});

3.2.2 ICON

只修改前面的就行,不用把png修改

image.png

3.2.3 Label

從左側工具欄拉下來後,顯示的名字

image.png

3.2.4 Node Name

修改下面兩處

  • js中需要註冊的頁面和Function
  • html中需要註冊的頁面,label,以及頁面的name

image.png

image.png

3.2.5 Node Attribute

  • category: (string) 节点出现的调色板类别
  • defaults: (object) 节点的可编辑属性。
  • credentials: (object) 节点的凭证属性。
  • inputs: (number) 节点有多少输入,要么0要么1。
  • outputs: (number) 节点有多少个输出。可以0或更多。
  • color: (string) 要使用的背景颜色。
  • paletteLabel: (string|function)调色板中使用的标签。
  • label: (string|function) 在工作区中使用的标签。
  • labelStyle: (string|function)应用于标签的样式。
  • inputLabels: (string|function)在悬停时添加到节点输入端口的可选标签。
  • outputLabels: (string|function)在悬停时添加到节点输出端口的可选标签。
  • icon:(字符串)要使用的图标。
  • align:(字符串)图标和标签的对齐方式。
  • button: (object)在节点的边缘添加一个按钮。
  • oneditprepare: (函数)在构建编辑对话框时调用。
  • oneditsave: (函数)在编辑对话框正常时调用。
  • oneditcancel: (函数)在取消编辑对话框时调用。
  • oneditdelete: (函数)在配置节点的编辑对话框中的删除按钮被按下时调用。
  • oneditresize: (函数)在调整编辑对话框大小时调用。
  • onpaletteadd: (函数)在将节点类型添加到调色板时调用。
  • onpaletteremove: (函数)从调色板中删除节点类型时调用。

3.2.6 Object Attribute

節點中對象的屬性

  • value:(任何类型)属性采用的默认值
  • required: (boolean)可选属性是否是必需的。如果设置为 true,则如果其值为 null 或空字符串,则该属性将无效。
  • validate: (function) optional可用于验证属性值的函数。
  • type: (string)可选,如果此属性是指向 配置节点的指针,则它标识节点的类型。
<script type="text/javascript">
    RED.nodes.registerType('Nolan',{
        category: 'function',
        color: '#a6bbcf',
        defaults: {
            name: {value:"",required:true},
            prefix: {value:"Demo_"}
        },
        credentials: {
            username: {type:"text"},
            password: {type:"password"}
        },
        inputs:1,
        outputs:1,
        icon: "cog.png",
        label: function() {
            return this.name||"Nolan";
        }
    });
</script>

<script type="text/x-red" data-template-name="Nolan">
    <style>
        .title-form{
            margin: 10px auto;
            
        }
    </style>
    <div class="form-row">
        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
        <input type="text" id="node-input-name" placeholder="Name">
    </div>
    <div class="title-form"><b>Show:</b></div>
    <div class="form-row">
        <label for="node-input-prefis"><i class="fa fa-tag"></i> Prefix</label>
        <input type="text" id="node-input-prefix">
    </div>
    <div class="title-form"><b>Login:</b> </div>

    <div class="form-row">
        <label for="node-input-username"><i class="fa fa-tag"></i> Username</label>
        <input type="text" id="node-input-username">
    </div>
    <div class="form-row">
        <label for="node-input-password"><i class="fa fa-tag"></i> Password</label>
        <input type="password" id="node-input-password">
    </div>
</script>                      

輸入值得校驗

image.png

3.2.7 Custom Edit Action

  • oneditprepare在显示对话框之前立即调用。常用
  • oneditsave当编辑对话框被确定时被调用。
  • oneditcancel在取消编辑对话框时调用。
  • oneditdelete当按下配置节点的编辑对话框中的删除按钮时调用。
  • oneditresize在调整编辑对话框的大小时调用。

3.3 Credentials

Node節點中輸入用戶名和密碼

1.html文件

<script type="text/javascript">
    RED.nodes.registerType('Nolan',{
        category: 'function',
        color: '#a6bbcf',
        defaults: {
            name: {value:"",required:true},
            prefix: {value:"Demo_"}
        },
        credentials: {
            username: {type:"text"},
            password: {type:"password"}
        },
        inputs:1,
        outputs:1,
        icon: "cog.png",
        label: function() {
            return this.name||"Nolan";
        }
    });
</script>

<script type="text/x-red" data-template-name="Nolan">
    <style>
        .title-form{
            margin: 10px auto;
            
        }
    </style>
    <div class="form-row">
        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
        <input type="text" id="node-input-name" placeholder="Name">
    </div>
    <div class="title-form"><b>Show:</b></div>
    <div class="form-row">
        <label for="node-input-prefis"><i class="fa fa-tag"></i> Prefix</label>
        <input type="text" id="node-input-prefix">
    </div>
    <div class="title-form"><b>Login:</b> </div>

    <div class="form-row">
        <label for="node-input-username"><i class="fa fa-tag"></i> Username</label>
        <input type="text" id="node-input-username">
    </div>
    <div class="form-row">
        <label for="node-input-password"><i class="fa fa-tag"></i> Password</label>
        <input type="password" id="node-input-password">
    </div>
</script>

<script type="text/x-red" data-help-name="Nolan">
    <p>A simple node that converts the message payloads into all lower-case characters</p>
    <p>Some useful help text to introduce the node.</p>
    <h3>Outputs</h3>
        <dl class="message-properties">
        <dt>payload
            <span class="property-type">string | buffer</span>
        </dt>
    <h3>Details</h3>
    <p>Some more information about the node.</p>
</script>

2.js文件

module.exports = function(RED) {
    function LowerCaseNode(config) {
        RED.nodes.createNode(this,config);
        var node = this;

        var username001 = this.credentials.username;
        var password001 = this.credentials.password;
        var prefix = config.prefix;

        //通过input接收上游节点的消息
        this.on('input', function(msg) {
            msg.payload = msg.payload.toLowerCase();
            node.send(msg);
            
            var  params = [];
            params.push({"prefix":prefix,"username":username001,"password":password001});
            var json = JSON.stringify(params);

            var msg1 = { payload:json}
            this.send(msg1);
            this.status({fill:"green",shape:"dot",text:"connected"});
        });
    }
    RED.nodes.registerType("Nolan",LowerCaseNode,{
        credentials: {
            username: {type:"text"},
            password: {type:"password"}
        
        }
    });
}

3.4 Button

3.5 API

RED API entry point returned by require('node-red');
  .init(server,settings) Initialises Node-RED
  .start() Start Node-RED
  .stop() Stop Node-RED
  .version() Returns the version
  .httpAdmin The admin express application
  .httpNode The node express application
  .server The http server instance
RED.auth Authentication middleware
    .needsPermission(permission) Middleware used to ensure a user has a specific permission
RED.comms  
    .publish(msg) Send a message to the editor
RED.library  
    .register(type) Register a type to the library
RED.log Logging services
    .addHandler(func) Add a log handler
    .log(msg) Log a message
    .info(msg) Log an info-level message
    .warn(msg) Log a warning-level message
    .error(msg) Log an error-level message
    .trace(msg) Log a trace-level message
    .debug(msg) Log a debug-level message
    .metric() Check if metrics are enabled in the runtime
    .audit(msg,req) Log an audit event
    ._(msg,options) Lookup NLS message
RED.nodes Core runtime api
    .getType(type) Get a type definition
    .getNode(id) Get a node configuration
    .eachNode(callback) Iterate over all ndoes
    .installModule(module) Install a new node module
    .uninstallModule(module) Remove a node module
    .enableNode(id) Enable a node set
    .disableNode(id) Disabled a node set
    .getNodeInfo(id) Get a node set’s information
    .getNodeList() Get the list of all available nodes
    .getModuleInfo(id) Get a node module’s information
    .getNodeConfigs() Get the HTML configurations of all active node sets
    .getNodeConfig(id) Get the HTML configuration of a specific node set
    .loadFlows() Load the active flow configuration
    .startFlows() Start the active flow configuration
    .stopFlows() Stop the active flow configuration
    .setFlows(flows,type) Set the active flow configuration
    .getFlows() Get the active flow configuration
    .addFlow(flow) Add a new flow to the active configuration
    .getFlow(id) Get a flow within the active configuration
    .updateFlow(id,flow) Update an existing flow in the active configuration
    .removeFlow(id) Remove a flow from the active configuration
    .addCredentials(id,credentials) Add a credentials entry for a node
    .getCredentials(id) Get the credentials entry for a node
    .deleteCredentials(id) Remove the credentials entry for a node
RED.settings Runtime settings
    .available() Check if settings are available
    .get(key) Get a setting value
    .set(key,value) Set a value in settings
RED.util Common utilities
    .cloneMessage(msg) Clone a message object
    .compareObjects(objA,objB) Compare two javascript objects
    .ensureBuffer(value) Ensure a value is a Buffer type
    .ensureString(value) Ensure a value is a String type
    .evaluateNodeProperty(value,type,node,msg) Evaluate a typed node property
    .generateId() Generate a new id value
    .getMessageProperty(msg,expr) Get a message property
    .setMessageProperty(msg,prop,value,createMissing) Set a message property
  • RED.init(server,settings)
  • RED.start()
  • RED.stop()
  • RED.version()
  • RED.httpAdmin
  • RED.httpNode
  • RED.server
  • RED.auth.needsPermission(permission)
  • RED.comms.publish(msg)
  • RED.library.register(type)
  • RED.log.addHandler(func)
  • RED.log.log(msg)
  • RED.log.info(msg)
  • RED.log.warn(msg)
  • RED.log.error(msg)
  • RED.log.trace(msg)
  • RED.log.debug(msg)
  • RED.log.metric()
  • RED.log.audit(msg,req)
  • RED.log._(msg,options)
  • RED.nodes.getType(type)
  • RED.nodes.getNode(id)
  • RED.nodes.eachNode(callback)
  • RED.nodes.installModule(module)
  • RED.nodes.uninstallModule(module)
  • RED.nodes.enableNode(id)
  • RED.nodes.disableNode(id)
  • RED.nodes.getNodeInfo(id)
  • RED.nodes.getNodeList()
  • RED.nodes.getModuleInfo(id)
  • RED.nodes.getNodeConfigs()
  • RED.nodes.getNodeConfig(id)
  • RED.nodes.loadFlows()
  • RED.nodes.startFlows()
  • RED.nodes.stopFlows()
  • RED.nodes.setFlows(flows,type)
  • RED.nodes.getFlows()
  • RED.nodes.addFlow(flow)
  • RED.nodes.getFlow(id)
  • RED.nodes.updateFlow(id,flow)
  • RED.nodes.removeFlow(id)
  • RED.nodes.addCredentials(id,credentials)
  • RED.nodes.getCredentials(id)
  • RED.nodes.deleteCredentials(id)
  • RED.settings.available()
  • RED.settings.get(key)
  • RED.settings.set(key,value)
  • RED.util.cloneMessage(msg)
  • RED.util.compareObjects(objA,objB)
  • RED.util.ensureBuffer(value)
  • RED.util.ensureString(value)
  • RED.util.evaluateNodeProperty(value,type,node,msg)
  • RED.util.generateId()
  • RED.util.getMessageProperty(msg,expr)
  • RED.util.setMessageProperty(msg,prop,value,createMissing)

3.6 Html

3.6.1 Disabled or Readonly

<input type="text" name="name" value="sss" disabled>

<input type="text" name="name" value="sss" readonly>

3.6.2 Json Convert

var jsonStr = '{"userName": "Nolan","userAge": 26,"isMale": true}'; 
var json = JSON.parse(jsonStr); 
var str = JSON.stringify(json);

3.6.3 Click Event

<button type="submit" id="btn">btn</button>

第一种:
$("#btn").click(function(event){})

第二种:
document.getElementById('#btn').addEventListener('click', function(){});

第三种:
$('#btn').bind('click', function();

第四种:
$("btn").on("click",function(){});

<button type="submit" id="btn" onclick="btn()">btn</button>

function btn(){}

3.7 JSON

JSON.parse

JSON.parse() 用来解析JSON字符串,得到对应的JavaScript值或对象

語法: JSON.parse(text[, reviver])

JSON.parse('5', function (key, value) {
  console.log(`key:${key}, value:${value}`)
})
// key:, value:5
JSON.parse('null', function (key, value) {
  console.log(`key:${key}, value:${value}`)
})
// key:, value:null
JSON.parse('{}', function (key, value) {
  console.log(`key:${key}, value:`, value)
})
// key:, value:{}
JSON.parse('[1, 2]', function (key, value) { 
  console.log(`key:${key}, value:`, value) 
})

JSON.stringify

JSON.stringify() 将一个JavaScript对象或值转换为JSON格式字符串。

語法: JSON.stringify(value[, replacer [, space]])

  • value:将要序列化成 一个JSON字符串的JavaScript对象或值。
  • replacer 可选,用于处理将要序列化的值。
  • space 可选,指定缩进用的空白字符串,用于美化输出。
const obj = {
  json: 'JSON',
  parse: 'PARSE',
  stringify: 'STRINGIFY'
}
JSON.stringify(obj, ['parse', 'stringify'])
// '{"parse":"PARSE","stringify":"STRINGIFY"}'

JSON.stringify({ json: 1, stringify: { val: 'rr'} }, (key, value) => {
  console.log(`key:${key},value:`, value)
  return value
}) 
// key:,value: {json: 1, stringify: {…}}
// key:json,value: 1
// key:stringify,value: {val: 'rr'}
// key:val,value: rr
// '{"json":1,"stringify":{"val":"rr"}}'

JSON.stringify({ json: 1, stringify: 'rr' }, (key, value) => {
  if (typeof value === 'number') {
    return 'ss'
  }
  return value
}) 
// '{"json":"ss","stringify":"rr"}'

JSON.stringify({ json: 1, stringify: 'rr' }, (key, value) => {
  if (typeof value === 'number') {
    value = undefined
  }
  return value
}) 
// '{"stringify":"rr"}'

測試

// 定义一个JSON对象 
var person = { 
    "name": "张三", 
    "age": 20, 
    "gender": "男", 
    "address": { "city": "北京", "street": "朝阳区" }, 
    "hobbies": ["篮球", "游泳", "音乐"] 
};
// 使用JSON.stringify方法将JSON对象转换为JSON字符串 
var personJsonString = JSON.stringify(person); 
// 输出JSON字符串 
console.log(personJsonString); 
// 使用JSON.parse方法将JSON字符串转换为JSON对象 
var personJson = JSON.parse(personJsonString); 
// 输出JSON对象 
console.log(personJson);

3.8 Context

nodered.org/docs/user-g…

Context scope levels:

  • Node - only visible to the node that set the value
  • Flow - visible to all nodes on the same flow (or tab in the editor)
  • Global - visible to all nodes

JS中如何使用的語法

image.png

3.8.1 Settings.js

啟動的時候,查看控制台log image.png

image.png

3.8.2 synchronous or asynchronous

synchronous

var count = context.get('count')||0;
count += 1;
context.set('count',count);
msg.count = count;
return msg;


var values = flow.get(["count", "colour", "temperature"]);
flow.set(["count", "colour", "temperature"], [123, "red", "12.5"]);

asynchronous

// Get single value
flow.get("count", function(err, myCount) { ... });

// Get multiple values
flow.get(["count", "colour"], function(err, count, colour) { ... })

// Set single value
flow.set("count", 123, function(err) { ... })

// Set multiple values
flow.set(["count", "colour"], [123, "red"], function(err) { ... })


context.get('count', function(err, count) {
    if (err) {
        node.error(err, msg);
    } else {
        // initialise the counter to 0 if it doesn't exist already
        count = count || 0;
        count += 1;
        // store the value back
        context.set('count',count, function(err) {
            if (err) {
                node.error(err, msg);
            } else {
                // make it part of the outgoing msg object
                msg.count = count;
                // send the message
                node.send(msg);
            }
        });
    }
});

3.8.3 FunctionGlobalContext

image.png

4. Error

4.1 [object Object]

    JSON.stringify(payload, (key, value) => {
        console.log(value)
    });