node-red教程 5 函数节点
5.1 函數(shù)控件介紹
函數(shù)控件在node-red中是重點(diǎn),也是難點(diǎn)。由于其功能強(qiáng)大,能做的事情很多,所以它重要;事實(shí)上,函數(shù)控件中的“函數(shù)”一詞,翻譯為中文“功能”也是可以的。但是,函數(shù)是需要直接編寫代碼的,所以說也是難點(diǎn)。
節(jié)點(diǎn)幫助
一個(gè)JavaScript函數(shù)塊,用來處理節(jié)點(diǎn)接收到的消息。
這些消息作為一個(gè)名為msg的JavaScript對象傳入。
按照慣例,它會有一個(gè)msg.payload屬性,包含消息正文。
函數(shù)被期望返回一個(gè)message對象(或多個(gè)消息對象),但是可以選擇不返回任何東西以阻止流。
詳細(xì)信息
有關(guān)編寫函數(shù)的更多信息,請參見在線文檔https://nodered.org/docs/writing-functions.html
發(fā)送消息
這個(gè)函數(shù)既可以使用“return”向流中的下一個(gè)節(jié)點(diǎn)傳遞消息,也可以調(diào)用node.send(messages)。
它可以返回或是發(fā)送
一個(gè)單一的消息對象——傳遞給連接到第一個(gè)輸出的節(jié)點(diǎn)
一組消息對象——傳遞給連接到相應(yīng)輸出的節(jié)點(diǎn)
如果數(shù)組的任何元素本身都是一組消息,那么多條消息就會被發(fā)送到相應(yīng)的輸出。
如果返回null,無論是單獨(dú)還是作為數(shù)組的元素,都不會傳遞任何消息。
日志和錯(cuò)誤處理
要記錄任何信息或報(bào)告錯(cuò)誤,可以使用以下功能:
node.log(“Log message”)
node.warn(“Warning”)
node.error(“Error”)
1
2
3
Catch節(jié)點(diǎn)也可以用來處理錯(cuò)誤。為了調(diào)用Catch節(jié)點(diǎn),將msg作為第二個(gè)參數(shù)傳遞給node.error:
5.2 使用函數(shù)控件實(shí)現(xiàn)多個(gè)輸出
前邊使用switch控件時(shí)我們已經(jīng)實(shí)現(xiàn)了根據(jù)不同的條件,來實(shí)現(xiàn)多個(gè)輸出。Switch控件是一種功能控件,而函數(shù)控件也是功能控件。甚至可以說,函數(shù)控件可以通過編程實(shí)現(xiàn)所有功能控件的功能。接下來,我們嘗試用函數(shù)控件實(shí)現(xiàn)多個(gè)輸出。
5.2.1 最簡單的函數(shù)控件用法
拖入一個(gè)inject、function與debug,無需任何修改,直接用線連接三個(gè)節(jié)點(diǎn)。
這里寫圖片描述
部署,并點(diǎn)擊inject的輸入按鈕,觀察調(diào)試窗口。可以看到debug節(jié)點(diǎn)打印的調(diào)試信息。
這里寫圖片描述
你可能會說,什么嘛,不加這個(gè)函數(shù)節(jié)點(diǎn),直接連接inject與debug節(jié)點(diǎn),不也是這個(gè)效果嘛!這個(gè)函數(shù)節(jié)點(diǎn)有什么用?
它的作用就是,把消息原封不動(dòng)輸出。原封不動(dòng)的輸出,也是一種功能,最簡單的功能。
我們雙擊函數(shù)節(jié)點(diǎn),來看一下里邊的內(nèi)容。
這里寫圖片描述
只有一行代碼,return msg,返回消息。
回過頭來,看函數(shù)控件的說明信息。用來處理節(jié)點(diǎn)接收到的消息,消息作為一個(gè)名為msg的對象傳入。可以使用“return”向下一個(gè)節(jié)點(diǎn)傳遞消息。也就是說,函數(shù)控件的輸入時(shí)msg對象,輸出也是msg對象。在輸出之前,可以對msg對象進(jìn)行處理。所謂對象,意思是這是一個(gè)msg實(shí)例,是具體的數(shù)據(jù),不是抽象的,更不是msg跟異性朋友處對象。
既然可以原封不動(dòng)返回msg,當(dāng)然也可以不返回。只要把語句改為return null即可。Null的意思是空值,也可以說沒有值。修改代碼為:
這里寫圖片描述
重新部署,無論現(xiàn)在如何點(diǎn)擊inject節(jié)點(diǎn)的輸入按鈕,debug節(jié)點(diǎn)都不會打印出任何消息了。
5.2.2 在函數(shù)節(jié)點(diǎn)中創(chuàng)建并返回多個(gè)消息
函數(shù)控件中,除了可以處理輸入的msg對象以外,也可以自己定義一些msg對象。另外,說明文件中,有介紹說function可以返回一個(gè)對象,或是用數(shù)組傳遞一組對象。我們先嘗試自行建立一組對象并傳遞。
修改函數(shù)節(jié)點(diǎn):取個(gè)合適的名稱,添加如下代碼,并把輸出改為兩路。
var msg1 = { payload:“first out of output 1” };
var msg2 = { payload:“second out of output 1” };
var msg3 = { payload:“third out of output 1” };
var msg4 = { payload:“only message from output 2” };
return [ [ msg1, msg2, msg3 ], msg4 ];
1
2
3
4
5
這里寫圖片描述
拖入兩個(gè)debug節(jié)點(diǎn),命名,并分別接到函數(shù)節(jié)點(diǎn)的兩路輸出去。然后點(diǎn)擊inject的按鈕,觀察調(diào)試窗口的現(xiàn)象。
這里寫圖片描述
這里寫圖片描述
我們發(fā)現(xiàn),OUT1節(jié)點(diǎn)一口氣收到了3條消息,OUT2節(jié)點(diǎn)收到了一條消息,且消息的內(nèi)容我們剛剛輸入的代碼有關(guān)系。跟輸入的消息沒有任何關(guān)系,因?yàn)檩斎氲氖菚r(shí)間戳。
關(guān)注最后一句并對比分析:
return msg;//一個(gè)返回值
return [ [ msg1, msg2, msg3 ], msg4 ];//一組返回值
1
2
可以得出結(jié)論,如果想得到多個(gè)返回值,需要把返回值放到英文的中括號里。在3.1.3小節(jié)里,恰好在inject的內(nèi)容里,輸入數(shù)組時(shí),也是放在中括號里。這說明,多個(gè)返回值需要放到一個(gè)數(shù)組中,數(shù)組用中括號括起來,用逗號間隔開。而數(shù)組元素的順序,也就是輸出對象的順序,比如剛剛的OUT1收到的是msg1,msg2與msg3,而OUT2收到的msg4。
另外,雖然名為數(shù)組(array),但是其邊的元素并不是數(shù)字,而是msg對象,所以,更貼切的叫法應(yīng)該是:對象組。
這里寫圖片描述
這個(gè)例子代碼如下:
[{“id”:“adaac427.ae09a8”,“type”:“function”,“z”:“a1f259d6.8791a8”,“name”:“兩路輸出”,“func”:“var msg1 = { payload:“first out of output 1” };\nvar msg2 = { payload:“second out of output 1” };\nvar msg3 = { payload:“third out of output 1” };\nvar msg4 = { payload:“only message from output 2” };\nreturn [ [ msg1, msg2, msg3 ], msg4 ];”,“outputs”:2,“noerr”:0,“x”:360,“y”:180,“wires”:[[“6144cc3f.854e34”],[“4f12a300.ec146c”]]},{“id”:“e49b03a7.395d1”,“type”:“inject”,“z”:“a1f259d6.8791a8”,“name”:"",“topic”:"",“payload”:"",“payloadType”:“date”,“repeat”:"",“crontab”:"",“once”:false,“onceDelay”:0.1,“x”:200,“y”:180,“wires”:[[“adaac427.ae09a8”]]},{“id”:“6144cc3f.854e34”,“type”:“debug”,“z”:“a1f259d6.8791a8”,“name”:“OUT1”,“active”:true,“tosidebar”:true,“console”:false,“tostatus”:false,“complete”:“payload”,“x”:510,“y”:160,“wires”:[]},{“id”:“4f12a300.ec146c”,“type”:“debug”,“z”:“a1f259d6.8791a8”,“name”:“OUT2”,“active”:true,“tosidebar”:true,“console”:false,“tostatus”:false,“complete”:“payload”,“x”:510,“y”:220,“wires”:[]}]
1
5.2.3 通過判斷語句進(jìn)行數(shù)據(jù)分類
Switch控件可以進(jìn)行數(shù)據(jù)的分流,它屬于功能控件。函數(shù)控件是功能控件里,功能最強(qiáng)的,它可以實(shí)現(xiàn)switch控件的功能。
第3章4節(jié)講解switch控件時(shí),使用過判斷數(shù)字的例子,這里用函數(shù)控件來實(shí)現(xiàn)它。
輸入與輸出不變,把函數(shù)節(jié)點(diǎn)替換掉switch節(jié)點(diǎn),并修改代碼如下:
這里寫圖片描述
分別點(diǎn)擊3個(gè)inject節(jié)點(diǎn)的輸入按鈕。可以再調(diào)試窗口觀察到以下現(xiàn)象。
這里寫圖片描述
可以看出,所有數(shù)據(jù)都根據(jù)判斷條件正確輸出,說明我們的任務(wù)完成了。代碼如下:
[{“id”:“50a42dcc.f47e44”,“type”:“inject”,“z”:“899b4619.356a88”,“name”:"",“topic”:"",“payload”:“100”,“payloadType”:“num”,“repeat”:"",“crontab”:"",“once”:false,“onceDelay”:0.1,“x”:330,“y”:160,“wires”:[[“d616421c.69733”]]},{“id”:“ea00b43e.c61ba8”,“type”:“inject”,“z”:“899b4619.356a88”,“name”:"",“topic”:"",“payload”:“10”,“payloadType”:“num”,“repeat”:"",“crontab”:"",“once”:false,“onceDelay”:0.1,“x”:330,“y”:220,“wires”:[[“d616421c.69733”]]},{“id”:“370ac143.d7c11e”,“type”:“inject”,“z”:“899b4619.356a88”,“name”:"",“topic”:"",“payload”:“1”,“payloadType”:“num”,“repeat”:"",“crontab”:"",“once”:false,“onceDelay”:0.1,“x”:330,“y”:280,“wires”:[[“d616421c.69733”]]},{“id”:“a9434442.ab3e98”,“type”:“debug”,“z”:“899b4619.356a88”,“name”:“OUT1”,“active”:true,“tosidebar”:true,“console”:false,“tostatus”:false,“complete”:“payload”,“x”:750,“y”:160,“wires”:[]},{“id”:“22fba15b.22857e”,“type”:“debug”,“z”:“899b4619.356a88”,“name”:“OUT2”,“active”:true,“tosidebar”:true,“console”:false,“tostatus”:false,“complete”:“payload”,“x”:750,“y”:220,“wires”:[]},{“id”:“82f1829b.b1b8a”,“type”:“debug”,“z”:“899b4619.356a88”,“name”:“OUT3”,“active”:true,“tosidebar”:true,“console”:false,“tostatus”:false,“complete”:“payload”,“x”:750,“y”:280,“wires”:[]},{“id”:“d616421c.69733”,“type”:“function”,“z”:“899b4619.356a88”,“name”:“判斷數(shù)字”,“func”:“if (msg.payload > 10 ){\n return [msg,null,null];\n}else if(msg.payload === 10 ){\n return [null,msg,null];\n}else{\n return [null,null,msg];\n}”,“outputs”:3,“noerr”:0,“x”:540,“y”:220,“wires”:[[“a9434442.ab3e98”],[“22fba15b.22857e”],[“82f1829b.b1b8a”]]}]
1
然后看一看通過主題來判斷的例子。跟判斷數(shù)字沒有多大的不同,只需要把被判斷的條件改為msg.payload就可以。
這里寫圖片描述
這段代碼出現(xiàn)了一個(gè)indexOf()函數(shù),它的作用就是檢查一下調(diào)用它的字符串,有沒有包含括號里的字符(或字符串)。如果包含的話,返回字符在字符串中首次出現(xiàn)的位置。如果沒有包含的話,返回-1。所以,if(msg.topic.indexOf(“e”) != -1)在包含的情況下成立。如圖配置并部署。
這里寫圖片描述
分別輸入3個(gè)inject節(jié)點(diǎn),結(jié)果如下:
這里寫圖片描述
這是跟3.4.4小節(jié)中,在選擇“接受第一條匹配消息后停止”的情況下,結(jié)果一樣。
代碼如下:
[{“id”:“e98b2a01.0b6228”,“type”:“function”,“z”:“a1f259d6.8791a8”,“name”:“判斷主題”,“func”:“if (msg.topic === “apple”) {\n return [ msg, null, null];\n} \nif(msg.topic === “banana”){\n return [ null, msg, null];\n}\nif(msg.topic.indexOf(“e”) != -1){\n return [null,null, msg ];\n}\n”,“outputs”:3,“noerr”:0,“x”:340,“y”:160,“wires”:[[“7cfcaea9.f501f”],[“6997f0e2.7d67d”],[“95d3ab47.6f79f8”]]},{“id”:“77880a51.e8f324”,“type”:“inject”,“z”:“a1f259d6.8791a8”,“name”:"",“topic”:“apple”,“payload”:“apple”,“payloadType”:“str”,“repeat”:"",“crontab”:"",“once”:false,“onceDelay”:0.1,“x”:130,“y”:100,“wires”:[[“e98b2a01.0b6228”]]},{“id”:“98875d47.089c5”,“type”:“inject”,“z”:“a1f259d6.8791a8”,“name”:"",“topic”:“banana”,“payload”:“banana”,“payloadType”:“str”,“repeat”:"",“crontab”:"",“once”:false,“onceDelay”:0.1,“x”:140,“y”:160,“wires”:[[“e98b2a01.0b6228”]]},{“id”:“a5a2ecfd.7f28f”,“type”:“inject”,“z”:“a1f259d6.8791a8”,“name”:"",“topic”:“orange”,“payload”:“orange”,“payloadType”:“str”,“repeat”:"",“crontab”:"",“once”:false,“onceDelay”:0.1,“x”:140,“y”:220,“wires”:[[“e98b2a01.0b6228”]]},{“id”:“7cfcaea9.f501f”,“type”:“debug”,“z”:“a1f259d6.8791a8”,“name”:“OUT1”,“active”:true,“tosidebar”:true,“console”:false,“tostatus”:false,“complete”:“payload”,“x”:530,“y”:100,“wires”:[]},{“id”:“6997f0e2.7d67d”,“type”:“debug”,“z”:“a1f259d6.8791a8”,“name”:“OUT2”,“active”:true,“tosidebar”:true,“console”:false,“tostatus”:false,“complete”:“payload”,“x”:530,“y”:160,“wires”:[]},{“id”:“95d3ab47.6f79f8”,“type”:“debug”,“z”:“a1f259d6.8791a8”,“name”:“OUT3”,“active”:true,“tosidebar”:true,“console”:false,“tostatus”:false,“complete”:“payload”,“x”:530,“y”:220,“wires”:[]}]
1
思考一下,apple顯然是包括了字符“e”的,但是點(diǎn)擊apple時(shí),為什么OUT3沒有收到apple的數(shù)據(jù)?
這是因?yàn)?#xff0c;編程的函數(shù)有一個(gè)特點(diǎn):見到return以后函數(shù)就結(jié)束了,即便return之后還有沒執(zhí)行的代碼。if (msg.topic === “apple”)成立以后就執(zhí)行了return,當(dāng)然不會管有沒有包含“e”的判斷條件了。
如果你想實(shí)現(xiàn)apple既要輸出給OUT1,又要輸出給OUT3的話,可以使用一個(gè)數(shù)組,在滿足if (msg.topic === “apple”)時(shí),元素1儲存apple;在滿足if(msg.topic.indexOf(“e”) != -1)時(shí),元素3存儲apple,只使用一次return,來返回?cái)?shù)組就可以了。你可以嘗試自己實(shí)現(xiàn)它。
后邊也會用到函數(shù)的send方法。
5.3 使用函數(shù)控件處理數(shù)據(jù)
上一小節(jié)使用函數(shù)控件進(jìn)行判斷與多個(gè)輸出的情況下,函數(shù)控件可能還沒有switch好用。但是在這一節(jié),函數(shù)控件的優(yōu)勢就能完全體現(xiàn)出來。接下來使用函數(shù)控件可以進(jìn)行數(shù)據(jù)的處理。
5.3.1 單個(gè)數(shù)字的計(jì)算
接下來嘗試用函數(shù)節(jié)點(diǎn)對數(shù)字進(jìn)行計(jì)算。拖入inject節(jié)點(diǎn),并把輸入的內(nèi)容改為數(shù)字;拖入debug節(jié)點(diǎn)用來觀察現(xiàn)象,拖入函數(shù)節(jié)點(diǎn)并做如下修改:
這里寫圖片描述
其中,var newMsg = {payload: msg.payload * 2 }語句的意思是,新建一個(gè)對象,名為newMsg,它有payload屬性,并且payload的值為msg.payload的兩倍。最后返回的是newMsg,也就是新建的這個(gè)對象。
這里寫圖片描述
部署并運(yùn)行,可以看到現(xiàn)象是,調(diào)試窗口顯示的數(shù)值是輸入的兩倍。說明函數(shù)節(jié)點(diǎn)的功能實(shí)現(xiàn)了。
這里寫圖片描述
我們知道,消息是通過msg對象傳過來的,可不可以不新建一個(gè)對象,直接修改msg.payload呢?當(dāng)然是可以的。
將函數(shù)節(jié)點(diǎn)內(nèi)的代碼修改為
msg.payload = msg.payload*2;
return msg;
1
2
部署,可以發(fā)現(xiàn)結(jié)果一樣正確。由于這個(gè)代碼實(shí)際的處理順序是從右向左,也就是msg.payload先乘以2,再賦值給msg.payload。出于方便理解的角度,我們總是用一個(gè)變量來暫時(shí)儲存一下msg.payload計(jì)算過的值。代碼修改為:
var temp = msg.payload*2;
msg.payload = temp;
return msg;
1
2
3
這段程序保存如下:
[{“id”:“d5052172.91827”,“type”:“inject”,“z”:“a1f259d6.8791a8”,“name”:"",“topic”:"",“payload”:“2333”,“payloadType”:“num”,“repeat”:"",“crontab”:"",“once”:false,“onceDelay”:0.1,“x”:140,“y”:180,“wires”:[[“ecfadc58.b48d4”]]},{“id”:“ecfadc58.b48d4”,“type”:“function”,“z”:“a1f259d6.8791a8”,“name”:“乘以二”,“func”:“var temp = msg.payload*2;\nmsg.payload = temp;\nreturn msg;”,“outputs”:1,“noerr”:0,“x”:310,“y”:180,“wires”:[[“811f3cdb.bf65b”]]},{“id”:“811f3cdb.bf65b”,“type”:“debug”,“z”:“a1f259d6.8791a8”,“name”:"",“active”:true,“tosidebar”:true,“console”:false,“tostatus”:false,“complete”:“false”,“x”:520,“y”:180,“wires”:[]}]
1
你可以自己來試一下除法該怎么應(yīng)用,將計(jì)算的代碼分別修改并觀察結(jié)果。
var temp = msg.payload%100;
var temp = msg.payload/100;
1
2
5.3.2 使用數(shù)組進(jìn)行數(shù)據(jù)的截取與組裝
通常,在實(shí)際通信的時(shí)候不會只傳遞一個(gè)數(shù)組,信息的傳遞依賴于數(shù)組,數(shù)組中不同位置的數(shù)字也會有不同的含義,例如,第一個(gè)數(shù)字表示ID,第二個(gè)數(shù)字表示數(shù)組長度,第三個(gè)數(shù)字表示溫度等等,一般會有一個(gè)通信協(xié)議來規(guī)定。所以,如何取出有用的數(shù)據(jù),或者按要求把數(shù)據(jù)進(jìn)行組裝很重要。
現(xiàn)在,假如收到了一串?dāng)?shù)據(jù),數(shù)據(jù)共16位,我們只用到后8位,前邊的8位都不要了,如何來操作?
這里寫圖片描述
通過分析可以得知:
ARR2[0] = ARR1[8];
ARR2[1] = ARR1[9];
……
ARR2[7] = ARR1[15];
1
2
3
4
但是寫代碼的時(shí)候一般不會這么復(fù)制粘貼。這是循環(huán)操作,用for語句可以增加效率。
var temp = new Buffer([0,0,0,0,0,0,0,0]);
for(var i = 0;i <8 ;i++)
temp[i] = msg.payload[i+8];
msg.payload = temp;
return msg;
1
2
3
4
5
我們新建一個(gè)temp數(shù)組,有8個(gè)元素并初始化為0;
通過for循環(huán),把msg.payload[i+8]的值賦給temp[i],i可以是0到7。
然后板temp作為msg的payload返回。
接下來添加inject與debug節(jié)點(diǎn)搭一個(gè)測試環(huán)境。Inject節(jié)點(diǎn)內(nèi)容為數(shù)組。
這里寫圖片描述
函數(shù)節(jié)點(diǎn)內(nèi)容
這里寫圖片描述
整個(gè)流程如下
這里寫圖片描述
[{“id”:“d5052172.91827”,“type”:“inject”,“z”:“a1f259d6.8791a8”,“name”:"",“topic”:“數(shù)組輸入”,“payload”:"[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]",“payloadType”:“bin”,“repeat”:"",“crontab”:"",“once”:false,“onceDelay”:0.1,“x”:140,“y”:180,“wires”:[[“37f18063.f0bdd”]]},{“id”:“811f3cdb.bf65b”,“type”:“debug”,“z”:“a1f259d6.8791a8”,“name”:"",“active”:true,“tosidebar”:true,“console”:false,“tostatus”:false,“complete”:“false”,“x”:490,“y”:180,“wires”:[]},{“id”:“37f18063.f0bdd”,“type”:“function”,“z”:“a1f259d6.8791a8”,“name”:“數(shù)據(jù)截?cái)唷?“func”:“var temp = new Buffer([0,0,0,0,0,0,0,0]);\nfor(var i = 0;i <8 ;i++)\ntemp[i] = msg.payload[i+8];\nmsg.payload = temp;\nreturn msg;\n”,“outputs”:1,“noerr”:0,“x”:300,“y”:180,“wires”:[[“811f3cdb.bf65b”]]}]
1
部署并觀察調(diào)試窗口如下
這里寫圖片描述
說明經(jīng)過函數(shù)節(jié)點(diǎn)以后,我們成功截取了數(shù)組的后8位。
接下來進(jìn)行數(shù)據(jù)的組裝。需求是,我們的原始數(shù)據(jù)是8位的,通信協(xié)議要求的數(shù)據(jù)是16位的,我們要把原始數(shù)據(jù)放在通信數(shù)據(jù)的后8位。邏輯跟剛剛的組裝正好相反。
這里寫圖片描述
以下是函數(shù)節(jié)點(diǎn)的代碼
var temp = new Buffer([170,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0]);
for(var i = 0;i <8 ;i++)
temp[8+i] = msg.payload[i];
msg.payload = temp;
return msg;
1
2
3
4
5
Inject節(jié)點(diǎn)的設(shè)置與現(xiàn)象,就請你自行導(dǎo)入流來觀察吧。
[{“id”:“d5052172.91827”,“type”:“inject”,“z”:“a1f259d6.8791a8”,“name”:"",“topic”:“數(shù)組輸入”,“payload”:"[0,1,2,3,4,5,6,7]",“payloadType”:“bin”,“repeat”:"",“crontab”:"",“once”:false,“onceDelay”:0.1,“x”:140,“y”:180,“wires”:[[“37f18063.f0bdd”]]},{“id”:“811f3cdb.bf65b”,“type”:“debug”,“z”:“a1f259d6.8791a8”,“name”:"",“active”:true,“tosidebar”:true,“console”:false,“tostatus”:false,“complete”:“false”,“x”:490,“y”:180,“wires”:[]},{“id”:“37f18063.f0bdd”,“type”:“function”,“z”:“a1f259d6.8791a8”,“name”:“數(shù)據(jù)截?cái)唷?“func”:“var temp = new Buffer([170,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0]); \nfor(var i = 0;i <8 ;i++)\ntemp[8+i] = msg.payload[i];\nmsg.payload = temp;\nreturn msg;\n”,“outputs”:1,“noerr”:0,“x”:300,“y”:180,“wires”:[[“811f3cdb.bf65b”]]}]
1
5.3.3 模擬溫度數(shù)值的計(jì)算
由于通信方式的限制,數(shù)據(jù)在發(fā)送時(shí),常常要轉(zhuǎn)換為8位的字符來發(fā)送。在數(shù)字電路里,只有高電平和低電平兩種情況,所以數(shù)據(jù)在發(fā)送時(shí),就只能使用1和0個(gè)數(shù)字。這個(gè)1或0,稱之為1位。通常,8位可以傳輸一個(gè)字符。2的8次方是256,所以小于256的數(shù)字,可以用8位來傳輸。而大于或等于256的數(shù)字,就要分成2個(gè)8位傳輸了。另外,8位的數(shù)據(jù)可以用兩個(gè)十六進(jìn)制的數(shù)來表示,比如0101 1010可以表示為0x5a,所以通常會用十六進(jìn)制來表示通信協(xié)議中的數(shù)。
例如,我們現(xiàn)在想傳輸十進(jìn)制的數(shù)字14859,大于256,所以要分包傳送。十進(jìn)制轉(zhuǎn)化為二進(jìn)制是0011 1010 0000 1011,在通過硬件發(fā)送數(shù)據(jù)時(shí),如果不考慮校驗(yàn)或者起始位以及高位還是地位在前,就只考慮數(shù)字的發(fā)送,那么總線上的電平可能是低低高高,高低高低,低低低低,高低高高。把這個(gè)數(shù)字寫成十六進(jìn)制,是0x3a與0x0b,或0x3a0b,0x用來表示這是個(gè)十六進(jìn)制的數(shù)字。0x3049可以通過這種方式換算成10進(jìn)制:數(shù)字拆成單個(gè)字符來分析,a到f的數(shù)對應(yīng)10到15,在第幾位上,就乘以幾個(gè)16。0x3a0b = 3×16×16×16+10×16×16+11=14859。或者直接使用16進(jìn)制進(jìn)行計(jì)算,0x3a0b=0x3a×256+0x0b
當(dāng)然,通信協(xié)議是可以進(jìn)行特殊的規(guī)定,例如表示4位的溫度,34.56°C,要通過十六進(jìn)制的數(shù)字進(jìn)行分包發(fā)送,就是0Xd80/100。我們現(xiàn)在規(guī)定,十六進(jìn)制的溫度高位×256+低位=溫度×100。接下來嘗試解析溫度的數(shù)據(jù)。
我們使用inject節(jié)點(diǎn)輸入數(shù)組[0xd,0x80],由于inject節(jié)點(diǎn)里不支持直接輸入十六進(jìn)制的數(shù)字,所以輸入[13,128]。這兩個(gè)數(shù)組的值是一樣的。
這里寫圖片描述
函數(shù)節(jié)點(diǎn)進(jìn)行如下修改
這里寫圖片描述
連線并部署,然后點(diǎn)擊inject節(jié)點(diǎn)的輸入按鈕,可以看到調(diào)試窗口輸出的正是我們期望的結(jié)果:34.56。
這里寫圖片描述
代碼如下:
[{“id”:“d5052172.91827”,“type”:“inject”,“z”:“a1f259d6.8791a8”,“name”:"",“topic”:“數(shù)組輸入”,“payload”:"[13,128]",“payloadType”:“bin”,“repeat”:"",“crontab”:"",“once”:false,“onceDelay”:0.1,“x”:140,“y”:180,“wires”:[[“37f18063.f0bdd”]]},{“id”:“811f3cdb.bf65b”,“type”:“debug”,“z”:“a1f259d6.8791a8”,“name”:"",“active”:true,“tosidebar”:true,“console”:false,“tostatus”:false,“complete”:“false”,“x”:490,“y”:180,“wires”:[]},{“id”:“37f18063.f0bdd”,“type”:“function”,“z”:“a1f259d6.8791a8”,“name”:“溫度計(jì)算”,“func”:“var temp = (msg.payload[0]*256+msg.payload[1])/100;\nmsg.payload = temp;\nreturn msg;\n”,“outputs”:1,“noerr”:0,“x”:300,“y”:180,“wires”:[[“811f3cdb.bf65b”]]}]
1
可以再添加一個(gè)節(jié)點(diǎn),把數(shù)字34.56轉(zhuǎn)為字符34.56攝氏度。
這里寫圖片描述
這里寫圖片描述
總結(jié)
以上是生活随笔為你收集整理的node-red教程 5 函数节点的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: node-red教程 7dashboar
- 下一篇: node-red教程2 第一条数据流