I've been playing with Raspberry Pi and Node for fun. I thought for a simple experiment what if I grabbed some user input to turn an LED on and off.
const readline = require('readline');
const log = console.log;
const five = require('johnny-five');
const raspi = require('raspi-io');
const board = new five.Board({
io: new raspi(),
});
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
board.on('ready', function() {
const led = new five.Led('P1-7');
const recursiveAsyncReadLine = function () {
rl.question('Command: ', function (answer) {
switch(answer) {
case 'on':
log('Got it! Your answer was: "', answer, '"');
led.on();
break;
case 'off':
log('Got it! Your answer was: "', answer, '"');
led.stop().off();
break;
default:
}
recursiveAsyncReadLine();
});
};
recursiveAsyncReadLine();
});
It works however I get 2 strange bugs. In the console output below you'll see it prompts for my input... I enter my input, then it repeats my input in a distorted string of text
(see Example 1). Then after my verification message is output (Got it! Your answer was: " on ") I am met with a ReferenceError: on is not defined (Example 2) even though the
LED lit up perfectly.
Command: on
oonn //Example 1
Got it! Your answer was: " on "
Command:
ReferenceError: on is not defined //Example 2
>> off
ooffff
Got it! Your answer was: " off "
Command:
ReferenceError: off is not defined
>> on
oonn
Got it! Your answer was: " on "
Command:
ReferenceError: on is not defined
>> off
ooffff
Got it! Your answer was: " off "
Command:
ReferenceError: off is not defined
>> on
oonn
Got it! Your answer was: " on "
Command:
ReferenceError: on is not defined
>> off
ooffff
Got it! Your answer was: " off "
Command:
ReferenceError: off is not defined
I am thinking this is not so much a Raspberry Pi/Johnny-five thing and just a plain old JavaScript or Node issue.
Any ideas?
Ok retracing my previous statement looks like your issue is probably
led.stop().off();
In examples for Johny-five they show
led.stop();
led.off();
http://johnny-five.io/examples/led/
Good luck, happy hacking :-)
What happens if you reduce to this (works for me)?
const readline = require('readline');
const log = console.log;
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const recursiveAsyncReadLine = function () {
rl.question('Command: ', function (answer) {
switch(answer) {
case 'on':
log('Got it! Your answer was: "', answer, '"');
break;
case 'off':
log('Got it! Your answer was: "', answer, '"');
break;
default:
}
recursiveAsyncReadLine();
});
};
recursiveAsyncReadLine();
If that works, that at least tells us it has something to do with the interaction with either raspi-io or johnny-five. Also where does this run, does this code execute on the pi, if so, do you enter the text directly on the pi or is this being entered remotely. If entered remotely what is the platform of the machine you are entering the text on?
Related
This is possible in Linux terminal because there is shell like fish that use different highlighting for input text. Is it possible to have something like this in Node.js. Or do I need to reimplement readLine library with this feature.
Does anyone know how to do this in Node.js? I was checking the code for fish on GitHub and it seems that the project use NCurses. Can I do the same in Node.js to have REPL where input text is in color?
EDIT:
I've tested this code from #MehdiBelbal solution:
var readline = require('readline');
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question("lips> ", function(code) {
console.log('\ncode is ' + code);
rl.close();
});
rl._writeToOutput = function _writeToOutput(stringToWrite) {
rl.output.write(stringToWrite.replace(/define/g, '\u001b[1;34mdefine\x1b[0m'));
};
but it don't highlight the word define after you type it, you need to type space (or any character) and delete it with backspace.
You can acheive this by overriding _writeToOutput method
The '\x1b[31m' is the console red color unicode
you need to add '\x1b[0m' is the reset,
it is necessary for the colors to stop at this position:
rl._writeToOutput = function _writeToOutput(stringToWrite) {
rl.output.write('\x1b[31m'+stringToWrite+'\x1b[0m');
};
colors unicodes:
Black: \u001b[30m.
Red: \u001b[31m.
Green: \u001b[32m.
Yellow: \u001b[33m.
Blue: \u001b[34m.
Magenta: \u001b[35m.
Cyan: \u001b[36m.
White: \u001b[37m.
code example:
var readline = require('readline');
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question("code: ", function(code) {
console.log('\ncode is ' + code);
rl.close();
});
// force trigger of _writeToOutput on each keystroke
process.stdin.on('keypress', (c, k) => {
// setTimeout is needed otherwise if you call console.log
// it will include the prompt in the output
setTimeout(() => {
rl._refreshLine();
}, 0);
});
rl._writeToOutput = function _writeToOutput(stringToWrite) {
rl.output.write(stringToWrite.replace(/define/g, '\u001b[1;34mdefine\x1b[0m'));
};
type "define" to have it in blue.
If you mean the console, i can suggest the extension Chalk.
Example using chalk:
const chalk = require("chalk");
//...
console.log(chalk.red("Red text, ") + "normal text");
This will log "Red text, " in red.
this is my message.test.js file.
var expect = require('expect');
var {generateMessage} = require('./message');
describe('generateMessage', () => {
it('should generate correct message object', () => {
var from = 'Jen';
var text = 'Some message';
var message = generateMessage(from, text);
expect(message.createdAt).toBeA('number');
expect(message).toInclude({from, text});
});
});
ERROR:
priya#priya-pro:~/node-chat-app$ npm test
node-chat-app#1.0.0 test /home/priya/node-chat-app
mocha server/**/*.test.js
generateMessage
1) should generate correct message object
0 passing (12ms)
1 failing
1) generateMessage
should generate correct message object:
TypeError: expect(...).toBeA is not a function
at Context.it (server/utils/message.test.js:12:31)
npm ERR! Test failed. See above for more details.
Help me...
The ownership of the expect library has been donated to jest from v21+. Since then some of the method names and their functionality has been changed. The following modification to code will help to overcome issue.
var expect = require('expect');
var {generateMessage} = require('./message');
describe('generateMessage', () => {
it('should generate correct message object', () => {
var from = 'Jen';
var text = 'Some message';
var message = generateMessage(from, text);
expect(typeof message.createdAt).toBe('number');
expect(message).toMatchObject({from, text});
});
});
In a similar way, I made a basic syntax error, my terminal was saying:
TypeError: sum(...).toBe is not a function.
Here's the code I was using in both my main.js file and my main.test.js file:
↓ main.js ↓
function sum(a, b){
return a + b
}
module.exports = sum;
↓ main.test.js ↓
const sum = require('./main')
test('adds two numbers together', ()=>{
expect(sum(2,2).toBe(4))
})
I kept thinking that my module.exports/require syntax was somehow wrong. After many attempts, I meticulously followed a Jest.js tutorial - and the unit test passed! I then compared it with my nonfunctional copy - and I spotted the error in my main.test.js file :
main.test.js
expect(sum(2,2).toBe(4))
what it needs to be is:
expect(sum(2,2)).toBe(4)
Notice the position of the parentheses - rather than chaining the .toBe() matcher to the expect() function, I was unwittingly passing .toBe() into the expect() function with my sum(2,2) value, resulting in : TypeError: sum(...).toBe is not a function !
A super obvious mistake in hindsight, but hopefully this helps someone in the future! :-)
I want to pipe content to file. Here's what I've wrote:
var fs = require('fs');
var Readable = require('stream').Readable;
var ws = fs.createWriteStream('xfiles.txt');
var rs = new Readable;
ws.on('finish', function() {
console.log('Written ' + ws.bytesWritten + ' ' + ws.path);
});
rs.push('foo bar baz');
rs.push('foo bar baz');
rs.push('foo bar baz');
rs.push(null);
rs.pipe(ws);
ws.end();
I expected the xfiles.txt to have 3 lines of 'foo bar baz'. But the output tells me that 0 bytes written, and when I check xfiles.txt it's empty.
What do I miss?
EDIT
Sorry, found the answer right after posting this question. The answer in this SO question solved my problem.
Found the answer just after posting this question. This SO question have the answer that also solved my problem.
What I have to do is to call ws.end() after the stream completes its async operation. So I have to put it inside a callback:
ws.on('end', function() {
ws.end();
});
So I'm using this example code from the NodeJS docs:
const readline = require('readline');
const rl = readline.createInterface(process.stdin, process.stdout);
console.log("Hello!");
rl.setPrompt('OHAI> ');
rl.prompt();
rl.on('line', (line) => {
switch(line.trim()) {
case 'hello':
console.log('world!');
break;
default:
console.log('Say what? I might have heard `' + line.trim() + '`');
break;
}
rl.prompt();
}).on('close', () => {
console.log('Have a great day!');
process.exit(0);
});
I'm on Windows, running NodeJS 6.0.0. When I run the file, it writes "Hello!", followed by the first "OHAI> ". So far so good. Now I try writing an arbitrary "asd". When I press enter, one of two things happens:
It prints:
asd
Say what? I might have heard 'asd'
OHAI>
It prints
Say what? I might have heard 'asd'
OHAI>
This only happens on the first input line. It seems to be completely random, however if, after I type node test.js, I press enter fast enough, sometimes I get a newline before the first "OHAI> " and it doesn't print my arbitrary input.
Is there something wrong with the example? Is it a bug in NodeJS? Even if it can't be fixed, I'd be relieved to know what causes it, since I've been pulling my hairs out for hours now.
This should solve the issue.
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
I'm still not sure why this happens, but I've found a way around it. It's a bit ugly, but it does the job.
var rl;
function cli() {
const readline = require('readline');
rl = readline.createInterface(process.stdin, process.stdout);
rl.prompt();
rl.on('line', exec_cmd);
rl.on('close', () => {
console.log('And now we part company.');
process.exit(0);
});
}
function fixfunc() {
//get first input
var input = process.stdin.read();
if (input == null)
return;
input = input.toString("utf-8");
//No longer needed, so remove the listener
process.stdin.removeListener('readable', fixfunc);
process.stdin.resume();
//do whatever you want with the input
exec_cmd(input);
//Initialize readline and let it do its job
cli();
}
process.stdin.pause();
process.stdin.on('readable', fixfunc);
process.stdout.write("> Welcome, Commander!\n> ");
What this basically does, is pause stdin, get the first input, manually call the parsing function and then initalize readline and let it do its job.
I am not able to read characters, strings or numbers. I'm starting to learn js and maybe it's an easy question but I cant answer it by myself. The code I'm using is:
var main = function()
{
"use strict";
var stdout = require("system").stdout;
var stdin = require("system").stdin;
stdout.write( "What is your name? " );
var name = stdin.readLine();
stdout.writeLine( "Hello, " + name );
}();
Thanks for your help and sorry if this question is quite silly.
You need to read the doc on how to use readline in Node --https://nodejs.org/api/readline.html#readline_readline:
var main = function()
{
"use strict";
var readline = require('readline');
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question("What is your name? ", function(answer) {
console.log("Hello ", answer);
rl.close();
});
}();
Vanilla Javascript doesn't support "read strings". However, if you have an html document, you could grab the input from a text box:
document.getElementById('textbox_id').value