Where can I find (or enable) an "interactive" console in node-red?

Disclaimer: Newbie Alert

Hi,

I am running Node-red (v1.2.9) on Raspbian (version 10 "buster"). I have connected an embedded device through USB-Serial (RS232) adapter that sends data on my USB port (/dev/ttyUSB0). After connecting the serial_in node to debug node, I am able to observe the data in debug node logs (initial booting messages from the device, refer image below).

However, I wish to send / type the login credentials (user ID and password) on the debug log but it doesn't allow me to do so. I have tried to enable publishing the data to the node red console but unfortunately, do not know where to find the it. The device that I have connected does not publish any further messages after booting, unless I log into it

I would like to interact with the node-red console much like a Linux terminal ; implying that I should be able to give commands and arguments to it and execute them. Coming back to my flow, I tried to inject the user_id using a simple inject and serial_out node combination (after I was saw that the logs have stopped and now I have to enter the login credentials), but it did not seem to work.

console_in_NR_issue_2

Any suggestions from the community are welcome.

UPDATE: I found that node-red-log shows info on the console but still it is not interactive i.e. I am unable to execute commands or pass login credentials to it. Looks like it only 'logs' info.

I suppose that's why it is called "node-red-log" :grin:

(Sorry, could not resist...)

@Simon01011 , yes I realized that (as well as my stupidity) :slight_smile:

Can you describe exactly what you are trying to achieve please in a bit more detail.

There isn't an interactive console. I guess you could sort of build one using the Dashboard to take a text input - send to serial request node - get response and display back on dashboard.

@Colin Sure, I am trying to read serial data from an embedded device (machine for example) using a USB-RS232 converter on my RaspPi. I want to display this data on my Node-Red dashboard and allow the user to send some commands (interact with the embedded device) through a text-input box. For example, I want to give the user the freedom to choose to display data from "sensor1" using a hypothetical command "getData sensor1". Hope you've more clarity now :slight_smile:

@dceejay thanks. Could you share an approach of what you would do? My current approach is to read the node-red-log file, filter the data from all the info and display it on my dashboard. However, things get tricky when I have multiple devices,sensors,cameras all generating logs in the same log file. What do you suggest? A custom logger maybe?

You said in the title that you wanted this in the editor, but now you are talking about the dashboard.

Well I'm talking about the dashboard - as I can't think of a way to do it in the editor.

I would go [ui-text-input node] -> [serial request node] -> [ui-text node] as a basic proof of concept

@Colin Maybe I was not clear about it in the beginning, apologies for that. I want to interact with the console from a dashboard, as I won't be interested to really see the editor every time.

@dceejay Ok, let me try something on these lines. Will get back to you with further updates.

UPDATE: Based on the suggestion by @dceejay, I was able to get the shell data on my dashboard.

However, it is badly formatted and I want it to look like a clean shell output like this (taken from PuTTY) -

GNU bash, version 4.4.12(1)-release (aarch64-poky-linux-gnu)
These shell commands are defined internally.  Type `help' to see this list.
Type `help name' to find out more about the function `name'.
Use `info bash' to find out more about the shell in general.
Use `man -k' or `info' to find out more about commands not in this list.

A star (*) next to a name means that the command is disabled.

 job_spec [&]                            history [-c] [-d offset] [n] or hist>
 (( expression ))                        if COMMANDS; then COMMANDS; [ elif C>
 . filename [arguments]                  jobs [-lnprs] [jobspec ...] or jobs >
 :                                       kill [-s sigspec | -n signum | -sigs>
 [ arg... ]                              let arg [arg ...]
 [[ expression ]]                        local [option] name[=value] ...
 alias [-p] [name[=value] ... ]          logout [n]
 bg [job_spec ...]                       mapfile [-d delim] [-n count] [-O or>
 bind [-lpsvPSVX] [-m keymap] [-f file>  popd [-n] [+N | -N]
 break [n]                               printf [-v var] format [arguments]
 builtin [shell-builtin [arg ...]]       pushd [-n] [+N | -N | dir]
 caller [expr]                           pwd [-LP]
 case WORD in [PATTERN [| PATTERN]...)>  read [-ers] [-a array] [-d delim] [->
 cd [-L|[-P [-e]] [-@]] [dir]            readarray [-n count] [-O origin] [-s>
 command [-pVv] command [arg ...]        readonly [-aAf] [name[=value] ...] o>
 compgen [-abcdefgjksuv] [-o option] [>  return [n]
 complete [-abcdefgjksuv] [-pr] [-DE] >  select NAME [in WORDS ... ;] do COMM>
 compopt [-o|+o option] [-DE] [name ..>  set [-abefhkmnptuvxBCHP] [-o option->
 continue [n]                            shift [n]
 coproc [NAME] command [redirections]    shopt [-pqsu] [-o] [optname ...]
 declare [-aAfFgilnrtux] [-p] [name[=v>  source filename [arguments]
 dirs [-clpv] [+N] [-N]                  suspend [-f]
 disown [-h] [-ar] [jobspec ... | pid >  test [expr]
 echo [-neE] [arg ...]                   time [-p] pipeline
 enable [-a] [-dnps] [-f filename] [na>  times
 eval [arg ...]                          trap [-lp] [[arg] signal_spec ...]
 exec [-cl] [-a name] [command [argume>  true
 exit [n]                                type [-afptP] name [name ...]
 export [-fn] [name[=value] ...] or ex>  typeset [-aAfFgilnrtux] [-p] name[=v>
 false                                   ulimit [-SHabcdefiklmnpqrstuvxPT] [l>
 fc [-e ename] [-lnr] [first] [last] o>  umask [-p] [-S] [mode]
 fg [job_spec]                           unalias [-a] name [name ...]
 for NAME [in WORDS ... ] ; do COMMAND>  unset [-f] [-v] [-n] [name ...]
 for (( exp1; exp2; exp3 )); do COMMAN>  until COMMANDS; do COMMANDS; done
 function name { COMMANDS ; } or name >  variables - Names and meanings of so>
 getopts optstring name [arg]            wait [-n] [id ...]
 hash [-lr] [-p pathname] [-dt] [name >  while COMMANDS; do COMMANDS; done
 help [-dms] [pattern ...]               { COMMANDS ; }

Till now, I have tried to use the built-in settings of the serial-out node (refer screenshot below), split them into lines with a "\n" and join them together using "\r". Could anyone please point out where I am going wrong?

Update: With some help from my colleague, I was able to arrange the output as single lines using a function block between the receive and output nodes with the following code.

var array = msg.payload.split('\n');
msg.payload = "";
for(var i = 0; i < array.length -1; i++){
    array[i] = "<p>" + array[i] + "</p>";
}
for(var x = 0 ; x < array.length -1; x++){
    msg.payload += array[x];
}
return msg

The problem was that the ui_text node needs html-style <p> </p> tags to specify new-lines (or paragraphs). My flow now looks like this -

[{"id":"2d9b9629.24ecea","type":"tab","label":"Console","disabled":false,"info":""},{"id":"3a8f8c11.6246cc","type":"serial in","z":"2d9b9629.24ecea","name":"Receive_msgs","serial":"beea37d3.019258","x":120,"y":260,"wires":[["8cc7f013.6c51d8"]]},{"id":"9a2ef1b2.9dc9b","type":"serial out","z":"2d9b9629.24ecea","name":"Publish_msgs","serial":"beea37d3.019258","x":380,"y":400,"wires":[]},{"id":"599afb4c.4665f4","type":"comment","z":"2d9b9629.24ecea","name":"Sending commands as text","info":"","x":150,"y":340,"wires":[]},{"id":"50df12b2.e0a49c","type":"ui_text_input","z":"2d9b9629.24ecea","name":"","label":"Input","tooltip":"","group":"e03c1e2.433b56","order":1,"width":0,"height":0,"passthru":true,"mode":"text","delay":"0","topic":"topic","topicType":"msg","x":90,"y":400,"wires":[["9a2ef1b2.9dc9b"]]},{"id":"98d1924b.8bdeb8","type":"comment","z":"2d9b9629.24ecea","name":"Receive and display commands","info":"","x":170,"y":200,"wires":[]},{"id":"8cc7f013.6c51d8","type":"function","z":"2d9b9629.24ecea","name":"String Splitter","func":"var array = msg.payload.split('\\n');\nmsg.payload = \"\";\nfor(var i = 0; i < array.length -1; i++){\n    array[i] = \"<p>\" + array[i] + \"</p>\";\n}\nfor(var x = 0 ; x < array.length -1; x++){\n    msg.payload += array[x];\n}\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":340,"y":260,"wires":[["d150de7b.f62918"]]},{"id":"d150de7b.f62918","type":"ui_text","z":"2d9b9629.24ecea","group":"d8596899.c56458","order":2,"width":"30","height":"10","name":"","label":"OUT","format":"{{msg.payload}}","layout":"col-center","x":550,"y":260,"wires":[]},{"id":"beea37d3.019258","type":"serial-port","serialport":"/dev/ttyUSB0","serialbaud":"115200","databits":"8","parity":"none","stopbits":"1","waitfor":"","dtr":"none","rts":"none","cts":"none","dsr":"none","newline":"250","bin":"false","out":"interbyte","addchar":"\\r","responsetimeout":"250"},{"id":"e03c1e2.433b56","type":"ui_group","name":"Console","tab":"5ba48494.46db94","order":1,"disp":true,"width":"30","collapse":false},{"id":"d8596899.c56458","type":"ui_group","name":"Default","tab":"ae47cffa.963c78","order":1,"disp":true,"width":"6","collapse":false},{"id":"5ba48494.46db94","type":"ui_tab","name":"Console","icon":"dashboard","order":4,"disabled":false,"hidden":false},{"id":"ae47cffa.963c78","type":"ui_tab","name":"Home","icon":"dashboard"}]

Here's an output from my dashboard -

I would now like to implement a scrolling text-box feature to show the most recent messages and scroll-down on the older ones. Have already started following this thread but I would appreciate any better leads, if available.

You could achieve this with a simple pre & code block. You can even have syntax highlighting and a MAX LENGTH buffer for scroll back.

example...

xSa2xxlzm7

Demo flow...

[{"id":"ca8f65c0.635a58","type":"ui_template","z":"553814a2.1248ec","group":"6d01ec93.b1d374","name":"","order":7,"width":"12","height":"8","format":"\n<!--<pre><code id=\"shell\" class=\"language-bash bash\" ng-bind=\"msg.payload\"></code></pre>-->\n<pre><code id=\"shell\" class=\"language-bash bash\"></code></pre>\n\n<script>\n    $(document).ready(function() {\n      $('#shell').each(function(i, e) {hljs.highlightElement(e)});\n    }); \n</script>\n\n\n<script>\n(function(scope) {\n  scope.$watch('msg', function(msg) {\n    if (msg) {\n        debugger\n      $(\"#shell\").text(msg.payload);\n      $('#shell').each(function(i, e) {hljs.highlightElement(e)});\n      //$(\"#shell\").scrollTop(function() { return this.scrollHeight; });\n      $(\"#shell\").closest(\".nr-dashboard-template\").scrollTop(function() { return this.scrollHeight; });\n    }\n  });\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":960,"y":1540,"wires":[[]]},{"id":"72d6a0f1.8fba2","type":"exec","z":"553814a2.1248ec","command":"","addpay":"payload","append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":750,"y":1560,"wires":[["bad9531a.ac42d"],[],[]]},{"id":"d42cac7d.f026a","type":"ui_template","z":"553814a2.1248ec","group":"dce9e7a2.d20c78","name":"highlighter","order":7,"width":0,"height":0,"format":"<link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.0.0/build/styles/default.min.css\">\n<script src=\"https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.0.0/build/highlight.min.js\"></script>\n<!-- and it's easy to individually load additional languages -->\n<script src=\"https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.0.0/build/languages/shell.min.js\"></script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"global","x":970,"y":1500,"wires":[[]]},{"id":"c0cb8d83.a207b","type":"ui_button","z":"553814a2.1248ec","name":"","group":"6d01ec93.b1d374","order":3,"width":"3","height":"1","passthru":false,"label":"time /T","tooltip":"","color":"","bgcolor":"","icon":"","payload":"time /T","payloadType":"str","topic":"topic","topicType":"msg","x":450,"y":1500,"wires":[["72d6a0f1.8fba2","bad9531a.ac42d"]]},{"id":"bad9531a.ac42d","type":"function","z":"553814a2.1248ec","name":"","func":"if(!msg.payload) return;\n\nconst MAXLINES = 200;\nlet data = context.get(\"data\") || [];\nif(msg.topic==\"clear\") {\n    data = [];\n} else {\n    const lines = msg.payload.split(\"\\n\");\n    data.push(...lines);\n    data = data.slice(-MAXLINES);\n}\ncontext.set(\"data\", data);\nmsg.payload = data.join(\"\\n\");\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":800,"y":1500,"wires":[["ca8f65c0.635a58"]]},{"id":"9f411e65.0e5dd","type":"ui_button","z":"553814a2.1248ec","name":"","group":"6d01ec93.b1d374","order":3,"width":"3","height":"1","passthru":false,"label":"where node","tooltip":"","color":"","bgcolor":"","icon":"","payload":"where node","payloadType":"str","topic":"topic","topicType":"msg","x":470,"y":1540,"wires":[["72d6a0f1.8fba2","bad9531a.ac42d"]]},{"id":"e1e64aad.590368","type":"ui_button","z":"553814a2.1248ec","name":"","group":"6d01ec93.b1d374","order":3,"width":"3","height":"1","passthru":false,"label":"where cmd","tooltip":"","color":"","bgcolor":"","icon":"","payload":"where cmd","payloadType":"str","topic":"topic","topicType":"msg","x":470,"y":1580,"wires":[["72d6a0f1.8fba2","bad9531a.ac42d"]]},{"id":"6750853f.a3036c","type":"ui_button","z":"553814a2.1248ec","name":"","group":"6d01ec93.b1d374","order":3,"width":"3","height":"1","passthru":false,"label":"clear","tooltip":"","color":"","bgcolor":"","icon":"","payload":"","payloadType":"str","topic":"clear","topicType":"str","x":450,"y":1620,"wires":[["bad9531a.ac42d"]]},{"id":"6d01ec93.b1d374","type":"ui_group","name":"UserEntry","tab":"5132060d.4cde48","order":2,"disp":true,"width":"12","collapse":false},{"id":"dce9e7a2.d20c78","type":"ui_group","name":"Object detection","tab":"5132060d.4cde48","order":1,"disp":true,"width":"7","collapse":false},{"id":"5132060d.4cde48","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]
1 Like

@Steve-Mcl , thanks for the flow. I just changed the exec node to serial nodes and it works really well! I really appreciate the work on html formatting.

Update - I thought it be useful if I share my flow. I have further implemented text input and reset on the flow shared by @Steve-Mcl .

[{"id":"efdcf8c8.4e3158","type":"tab","label":"Console","disabled":false,"info":""},{"id":"e3cd3705.3ca988","type":"ui_template","z":"efdcf8c8.4e3158","group":"e03c1e2.433b56","name":"","order":7,"width":"12","height":"10","format":"\n<!--<pre><code id=\"shell\" class=\"language-bash bash\" ng-bind=\"msg.payload\"></code></pre>-->\n<pre><code id=\"shell\" class=\"language-bash bash\"></code></pre>\n\n<script>\n    $(document).ready(function() {\n      $('#shell').each(function(i, e) {hljs.highlightElement(e)});\n    }); \n</script>\n\n\n<script>\n(function(scope) {\n  scope.$watch('msg', function(msg) {\n    if (msg) {\n        debugger\n      $(\"#shell\").text(msg.payload);\n      $('#shell').each(function(i, e) {hljs.highlightElement(e)});\n      //$(\"#shell\").scrollTop(function() { return this.scrollHeight; });\n      $(\"#shell\").closest(\".nr-dashboard-template\").scrollTop(function() { return this.scrollHeight; });\n    }\n  });\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":780,"y":580,"wires":[[]]},{"id":"f2b86b4c.37c9e","type":"ui_template","z":"efdcf8c8.4e3158","group":"dce9e7a2.d20c78","name":"highlighter","order":7,"width":0,"height":0,"format":"<link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.0.0/build/styles/default.min.css\">\n<script src=\"https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.0.0/build/highlight.min.js\"></script>\n<!-- and it's easy to individually load additional languages -->\n<script src=\"https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.0.0/build/languages/shell.min.js\"></script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"global","x":790,"y":520,"wires":[[]]},{"id":"ff960014.52bfe8","type":"function","z":"efdcf8c8.4e3158","name":"","func":"if(!msg.payload) return;\n\nconst MAXLINES = 200;\nlet data = context.get(\"data\") || [];\nif(msg.topic==\"clear\") {\n    data = [];\n} else {\n    const lines = msg.payload.split(\"\\n\");\n    data.push(...lines);\n    data = data.slice(-MAXLINES);\n}\ncontext.set(\"data\", data);\nmsg.payload = data.join(\"\\n\");\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":520,"y":580,"wires":[["e3cd3705.3ca988"]]},{"id":"d7dbd290.fb8418","type":"serial in","z":"efdcf8c8.4e3158","name":"Output","serial":"beea37d3.019258","x":130,"y":620,"wires":[["4be377aa.a14708","ff960014.52bfe8"]]},{"id":"c4d1c00c.3e05f8","type":"serial out","z":"efdcf8c8.4e3158","name":"Input","serial":"beea37d3.019258","x":750,"y":920,"wires":[]},{"id":"c3c385c9.a0cdd8","type":"ui_text_input","z":"efdcf8c8.4e3158","name":"","label":"","tooltip":"","group":"e03c1e2.433b56","order":4,"width":"10","height":"2","passthru":false,"mode":"text","delay":"0","topic":"topic","topicType":"msg","x":280,"y":860,"wires":[["c4d1c00c.3e05f8"]]},{"id":"4be377aa.a14708","type":"function","z":"efdcf8c8.4e3158","name":"clear_txt_field","func":"if(msg.payload.length!=0)\n    msg.payload=\"\"\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","x":140,"y":740,"wires":[["c3c385c9.a0cdd8"]]},{"id":"4635c501.7f3784","type":"ui_button","z":"efdcf8c8.4e3158","name":"Ctrl+C","group":"e03c1e2.433b56","order":3,"width":"3","height":"1","passthru":false,"label":"Ctrl+c","tooltip":"","color":"white","bgcolor":"red","icon":"","payload":"^C","payloadType":"str","topic":"","topicType":"str","x":150,"y":920,"wires":[["c4d1c00c.3e05f8"]]},{"id":"39b35ec2.5438c2","type":"ui_button","z":"efdcf8c8.4e3158","name":"","group":"e03c1e2.433b56","order":3,"width":"3","height":"1","passthru":false,"label":"clear","tooltip":"","color":"white","bgcolor":"green","icon":"","payload":"","payloadType":"str","topic":"clear","topicType":"str","x":310,"y":480,"wires":[["ff960014.52bfe8"]]},{"id":"532c5c8b.85296c","type":"comment","z":"efdcf8c8.4e3158","name":"","info":"","x":320,"y":440,"wires":[]},{"id":"18cc3e2a.47f4a2","type":"comment","z":"efdcf8c8.4e3158","name":"reset text field to empty","info":"","x":360,"y":740,"wires":[]},{"id":"94db8a04.a53068","type":"comment","z":"efdcf8c8.4e3158","name":"Send cmnds as string ","info":"","x":920,"y":920,"wires":[]},{"id":"e03c1e2.433b56","type":"ui_group","name":"Console","tab":"5ba48494.46db94","order":1,"disp":true,"width":"12","collapse":false},{"id":"dce9e7a2.d20c78","type":"ui_group","name":"Object detection","tab":"5132060d.4cde48","order":1,"disp":true,"width":"7","collapse":false},{"id":"beea37d3.019258","type":"serial-port","serialport":"/dev/ttyUSB0","serialbaud":"115200","databits":"8","parity":"none","stopbits":"1","waitfor":"","dtr":"none","rts":"none","cts":"none","dsr":"none","newline":"800","bin":"bin","out":"interbyte","addchar":"\\n","responsetimeout":"1000"},{"id":"5ba48494.46db94","type":"ui_tab","name":"Console","icon":"dashboard","order":4,"disabled":false,"hidden":false},{"id":"5132060d.4cde48","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]

@Steve-Mcl , So I noticed some unusual chars spread across my dashboard output after I run simple commands like ls (highlighted with black box)

To investigate the issue further, I accessed the serial-device using PuTTY on my laptop and came to a conclusion that colored text (blue) from the shell was not interpreted properly.

PuTTY snap

I suspect that the colorization would be indicating some special properties/rights for the folder (but not completely sure). Do you have any suggestions?

I think you can disable colored output for ls. Look into the file .bashrc in your home directory. There should be a section called "enable color support for ls" or so.

@Simon01011 I found a great discussion on StackOverflow about what the symbols imply. In my case, it simply means that "diags" is a directory.

I would surely try to disable the colors as per your suggestion, but it would be great to know if it is possible to incorporate some color coding to differentiate between files and directories using the html code shared by Steve.

The issue is the ANSI codes returned by the terminal are not recognised by HTML. There are libs on NPM to convert them to HTML but will take some work to get going.

For now, I would look to disabling ANSI color codes on the terminal.