友链
导航
These are the good times in your life,
so put on a smile and it'll be alright
友链
导航
A visual tool for wiring the Internet of Things
RED.nodes.registerType()
注册同名 node 会出错停止 flow 加载disableEditor
optionnpm install node-red-contrib-powermate
每个 function 中可以使用的变量如下:
msg
,即输入context
,本 function node 每次执行时共享的对象context.global
, 所有 function nodes 间共享的对象// For example, the built-in os module can be // made available to, all functions: functionGlobalContext: { osModule:require('os') }
console
- useful for making calls to console.log whilst debuggingutil
- the Node.js util moduleBuffer
- the Node.js Buffer module
function 可 return []
,同时可设置 outputs 为 n,设置后,function 便可接出多个 output,每个 output 的输入为 function 返回数组的第 n 个元素
General guidance:
Components:
Example:
module.exports = function(RED) { function LowerCaseNode(config) { RED.nodes.createNode(this,config); var node = this; this.on('input', function(msg) { msg.payload = msg.payload.toLowerCase(); node.send(msg); }); } RED.nodes.registerType("lower-case",LowerCaseNode); }
node 可以设置 button 和 badge,详细用法如下:
// 在 node.html 中... RED.nodes.registerType('MyNode',{ // ... defaults: { active: {value:true}, }, badge: function() { // badge 就是定义函数返回 text 这种用法... return 'badge'; }, onbadgeclick: function() { console.log('onbadgeclick'); }, // node 整体 align right,button 的 toggle 显示效果更好 aligh: "right", button: { toggle: "active", // toggle 可关联一项 node 的属性 onclick: function() { console.log('button.onclick'); } } };
inject
与后台是通过 AJAX d3.xhr()
通信的 button: { onclick: function() { var label = (this.name||this.payload).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"); d3.xhr("inject/"+this.id).post(function(err,resp) { if (err) { // error handle } else if (resp.status == 200) { RED.notify("Successfully injected: "+label,"success"); } else { RED.notify("<strong>Error</strong>: unexpected response: ("+resp.status+") "+resp.response,"error"); } }); } }
debug
与后台是通过 RED.comms
的 pub/sub
通信的 $ grep -nr 'RED.comms' nodes/ nodes/core/core/58-debug.js:89: RED.comms.publish("debug",msg); nodes/core/core/58-debug.html:173: RED.comms.subscribe("debug",handleDebugMessage);
RED.comms
推送的$ grep -nr 'comms.publish' red/ red/nodes/Node.js:147: comms.publish("status/"+this.id,status,true); $ grep -nr 'comms.sub' public/ public/red/main.js:159: RED.comms.subscribe("status/#",function(topic,msg) {
Node-RED : Embedding into an existing app
使用 express 的方式如下:
var http = require('http'); var express = require("express"); var RED = require("node-red"); // Create an Express app var app = express(); // Add a simple route for static content served from 'public' app.use("/",express.static("public")); // Create a server var server = http.createServer(app); // Create the settings object var settings = { httpAdminRoot:"/red", httpNodeRoot: "/api", userDir:"/home/nol/.nodered/" }; // Initialise the runtime with a server and settings RED.init(server,settings); // Serve the editor UI from /red app.use(settings.httpAdminRoot,RED.httpAdmin); // Serve the http nodes UI from /api app.use(settings.httpNodeRoot,RED.httpNode); server.listen(8000); // Start the runtime RED.start();
目前只有 standalone 模式可以使用 headless mode:
node-red/red.js
)httpAdminRoot: false,
和 httpNodeRoot: false,
httpRoot: false,
node red.js -s settings_headless.js
headless + embedded 的运行方式如下:
var RED = require('node-red'); var settings = { httpAdminRoot: false, httpNodeRoot: false // 不设置应该也可以 }; /** * the 1st param should be a http server, headless mode left null */ RED.init(null, settings); RED.start();
参考:
希望可以有 “前台 httpAdmin + 生成 json 但不运行的后台” 的运行 mode,但现在没有,github issues 中也没有人提过。而邮件组讨论中作者说过:
We are not actively looking at separating the UI and runtime, so any discussion of changing the communication between the two is premature.
所以需要自己想办法,比如就运行完整的 RED,但 watch flow.json,发现改变后 somehow push 到 runtime。
目前发现 node-red 并无很完备的配置检查方案,以 function 为例,如果 function 有语法/运行时错误,在点 deploy 后,保存都是成功的(一闪的绿条),立即加载会发现语法错误,但运行时错误必须运行到才会发现。
以下为 release 0.8.1 下的分析
require('node-red')
的入口为 red/red.js
, 它会 export RED
对象。注意是对象而非 constructorRED
一般的用法是 var RED = require("node-red"); var server = http.createServer(); RED.init(server,settings); RED.start();
server.js
)中,RED 根据 setting
,使用 express 创建 app
(封装在 ui.js
) 和 nodeApp
, 其中 app
是 admin 界面,而 nodeApp
是一个 RED 的 http node,供 flow 相关的 I/O 使用server.start()
,逻辑如下 function start() { var RED = require("./red"); var defer = when.defer(); storage.init(settings).then(function() { redNodes.init(settings,storage); // 包括: // credentials.init(storage); // flows.init(storage); // registry.init(_settings); // registry 是与 RED 使用的 nodes 的类型相关的部分 redNodes.load().then(function(nodeErrors) { // 即 registry.load(),读取所有可用的 nodes if (nodeErrors.length > 0) { // log errors } defer.resolve(); redNodes.loadFlows(); // 即 flows 中的 flows.load(),具体操作为 // storage.getFlows().then(credentials.load()).then(parseConfig(flows)) // 在 parseConfig() 中,会将 flows 中用到的 nodes 按类型 new, // 所有的 nodes run 了 flow 也就 run 了 }); // 使用 ws 开启与 browser 的实时通信 comms.start(); }); // start 整体是支持 promise 的 return defer.promise; }
var parseConfig = function() { // 检查 missing types // 如果有 missing types,则不 run nodes,报错返回 events.emit("nodes-starting"); // 实例化所有 node for (i=0;i<activeConfig.length;i++) { var nn = null; nt = typeRegistry.get(activeConfig[i].type); nn = new nt(activeConfig[i]); // 循环中并没保留 nn 的引用?难道不会被 GC 掉么? } // Clean up any orphaned credentials // credentials 都是干嘛的还不清楚 credentials.clean(flowNodes.get); events.emit("nodes-started"); }
node-red 中有很多类似
module.exports.__defineGetter__("app", function() { return app });''
的用法,作用为暴露出 getter(且 getter 方法不可修改)
flows.json 是对象数组,没有嵌套关系
[// tab 也会在 flows.json 中,但在 flow 启动时不会 new Node() {"type":"tab", "id":"d80082a9.27ff8", "label":"Sheet 1"}, // 之后是每个 node,每个 node 的必备信息包括 type, name, x, y, z(z 即 tab) {"id":"e9c6ec99.16391", "type":"inject", "name":"", "topic":"", "payload":"", "payloadType":"date", "repeat":"", "crontab":"", "once":false, "x":72, "y":163, "z":"d80082a9.27ff8", // wires 记录了本 node 的 output 连接的 nodes "wires":[["ba3f6475.45c098"]]}, {"id":"ba3f6475.45c098", "type":"debug", "name":"", "active":true, "console":false, "complete":false, "x":247, "y":169, "z":"d80082a9.27ff8", "wires":[]}]
var date = new Date(msg.payload); msg.payload = date.toString(); return msg;
Error: Lost connection to server
和 can't establish a connection to the server at ws://localhost:1880/comms
,则可能是代理导致 ws 不正常造成