Reading Arduino data using WebSocket with HTML & nodejs - html

I can't quite grasp the last step in this puzzle. Everything compiles, and it is "bug-free". This is my first foray into communications/full-stack and I have been stumped despite numerous excellent tutorials.
[WORKING] Arduino reads and interprets sensor data
[WORKING] index.js acquires data with serial communication over USB
[WORKING] index.js creates a WebSocket connection using nodejs
[WORKING] index.html performs the WebSocket handshake
[WORKING] index.html uses Plotly to create a real-time line graph
[WIP] index.html passes through the Arduino data in the Plotly function
Chopped down index.html:
<script src="server/plotly.min.js"></script>
<script>
//connection to the web socket server
const ws = new WebSocket("ws://localhost:5000");
let foo = 0.0;
//working
ws.addEventListener("open", () => {
console.log("We Are Connected");
ws.send("TestData");
});
//working
ws.addEventListener("message", e => {
console.log(e);
console.log("Data Recieved! Success.");
});
</script>
Rest of the file is just the graphing function which I would like to pass through Arduino data.
index.js
const WebSocket = require("ws");
const wss = new WebSocket.Server({ port: 5000 });
//create a serial port that allows serial connection from Arduino
let SerialPort = require("serialport");
let port = new SerialPort('COM4', { baudRate: 9600 });
let Readline = require("#serialport/parser-readline");
let parser = port.pipe(new Readline({ delimiter: '\n' }));
wss.on("connection", ws => {
//working
console.log("New Client Connection");
//this is what I need to passthrough my Plotly arg
parser.on("data", data => {
//event is firing but can't get client to grab this. Console logs data correctly.
console.log(RPM: ${data});
});
//working on both ends
ws.on("message", data => {
console.log("TEST")
ws.send(data);
});
//doesn't log?
port.on("open", () => {
console.log("Serial Port Open");
});
});
//working
console.log("The server is ON");
I'm looking for a strategy or method to grab the sensor data in my HTML file. Is it something simple conceptually I am missing? Thank you.

You established a websocket server, and it is works. If you want to send message to websocket, define a socket to the websocket server, get out the Serial part from websocket server, and run is standalone, and send data from this to the websocket.
Like this:
const http = require('http');
const WebSocketServer = require('websocket').server;
const server = http.createServer();
server.listen(5000);
const wsServer = new WebSocketServer({
httpServer: server
});
let SerialPort = require("serialport");
var serialPort = new SerialPort("COM5", {
baudRate: 9600,
parser: new SerialPort.parsers.Readline("\n")
});
var connection;
wsServer.on('request', function(request) {
connection = request.accept(null, request.origin);
connection.on('message', function(message) {
console.log('Received Message:', message.utf8Data);
connection.sendUTF('Hi this is WebSocket server!');
});
connection.on('close', function(reasonCode, description) {
console.log('Client has disconnected.');
});
});
serialPort.on('open',function(){
//connection.sendUTF('Hi this is WebSocket server!');
console.log('open');
serialPort.on('data', function(data){
readData = data.toString();
console.log("N<", readData);
if( typeof connection!="undefined")
connection.sendUTF( readData);
});
});

Related

The action did not produce a valid response and exited unexpectedly

I want to call a Node-RED flow from IBM Cloud Functions.
const https = require('https');
function main(params) {
const path = "/" + params.route + "?" + params.query_params ;
const options = {
hostname: params.hostname,
path: path,
port: 443,
method: 'GET'
};
return new Promise((resolve, reject) => {
https.get(options, (resp) => {
resp.on('data', (d) => {
let s = d.toString();
obj = JSON.parse(s);
resolve({ "gw_result": obj })
});
});
})
}
In the Node-RED flow I'm using a HTTP request to get data from another server. For test purposes I used a GET request to google.com but have same results using another Node-RED endpoint.
As soon as I invoke the web action I get the error message "The action did not produce a valid response and exited unexpectedly". The output of the Node-RED flow appears some seconds later in the web action's log although the Node-RED flow works properly and promptly (I used debug Node-RED debug nodes to check this).
The https GET request to Node-RED works well when I replace the http request in Node-RED by something else, e.g. a Function node, even when I use a Delay node to delay the response for a second or so.
This code works, although google.com does not return an object, of course.
var rp = require('request-promise');
function main(params) {
var uri = params.hostname + params.route + params.query_params
return new Promise(function (resolve, reject) {
rp(uri)
.then(function (parsedBody) {
obj = JSON.parse(parsedBody);
resolve({ "gw_result": obj
});
})
.catch(function (err) {
resolve({ message: 'failed!!', error: err.toString() });
});
});
}

How to get sensor data over TCP/IP in nodejs?

I have a nodejs app with socket.io. To test this, save the below listing as app.js. Install node, then npm install socket.io and finally run on command prompt: node app.js
var http = require('http'),
fs = require('fs'),
// NEVER use a Sync function except at start-up!
index = fs.readFileSync(__dirname + '/index.html');
// Send index.html to all requests
var app = http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(index);
});
// Socket.io server listens to our app
var io = require('socket.io').listen(app);
// Send current time to all connected clients
function sendTime() {
io.sockets.emit('time', { time: new Date().toJSON() });
}
// Send current time every 10 secs
setInterval(sendTime, 5000);
// Emit welcome message on connection
io.sockets.on('connection', function(socket) {
socket.emit('welcome', { message: 'Welcome!' });
socket.on('i am client', console.log);
});
app.listen(3000);
This code sends data to the file index.html. After running the app.js, open this file in your browser.
<!doctype html>
<html>
<head>
<script src='http://code.jquery.com/jquery-1.7.2.min.js'></script>
<script src='http://localhost:3000/socket.io/socket.io.js'></script>
<script>
var socket = io.connect('//localhost:3000');
socket.on('welcome', function(data) {
$('#messages').html(data.message);
socket.emit('i am client', {data: 'foo!'});
});
socket.on('time', function(data) {
console.log(data);
$('#messages').html(data.time);
});
socket.on('error', function() { console.error(arguments) });
socket.on('message', function() { console.log(arguments) });
</script>
</head>
<body>
<p id='messages'></p>
</body>
</html>
The data sent right now is the current time and index.html works fine, updates the time every five seconds.
I want to modify the code so that, it reads my sensor data over TCP. My sensors are connected thru a data acquisition system and relays the sensor data over IP: 172.16.103.32 port:7700. (This is over LAN, so will not the accessible to you.)
How can this be implemented in nodejs?
Is SensorMonkey a viable alternative ? If so, any pointers on how to go about using it?
I have a decent hack that is working right now, for which I request the readers to comment on....
var net = require('net'),
http = require('http'),
port = 7700, // Datalogger port
host = '172.16.103.32', // Datalogger IP address
fs = require('fs'),
// NEVER use a Sync function except at start-up!
index = fs.readFileSync(__dirname + '/index.html');
// Send index.html to all requests
var app = http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(index);
});
// Socket.io server listens to our app
var io = require('socket.io').listen(app);
// Emit welcome message on connection
io.sockets.on('connection', function(socket) {
socket.emit('welcome', { message: 'Welcome!' });
socket.on('i am client', console.log);
});
//Create a TCP socket to read data from datalogger
var socket = net.createConnection(port, host);
socket.on('error', function(error) {
console.log("Error Connecting");
});
socket.on('connect', function(connect) {
console.log('connection established');
socket.setEncoding('ascii');
});
socket.on('data', function(data) {
console.log('DATA ' + socket.remoteAddress + ': ' + data);
io.sockets.emit('livedata', { livedata: data }); //This is where data is being sent to html file
});
socket.on('end', function() {
console.log('socket closing...');
});
app.listen(3000);
References:
Socket.io Website - www.socket.io - Its the buzzword now.
TCP Socket Programming
Nodejs "net" module
Simplest possible socket.io example.

Web application using websockets and node.js

I'm new to HTML5 and node.js. I'm trying to create a very basic client-server application. Here is the code.
Server side (node.js):
var net = require('net');
var server = net.createServer(function(c) {
console.log('client connected');
c.setEncoding('utf8');
c.on('end', function() {
console.log('client disconnected');
});
c.on('data', function(data) {
console.log(data);
c.write("Got it");
});
});
server.listen(9998);
Client side (websockets):
<!DOCTYPE html>
<html>
<head>
<script>
try {
var ws = new WebSocket('ws://127.0.0.1:9998');
ws.onopen = function() {
ws.send("Message to send");
alert("Message is sent...");
};
ws.onmessage = function (evt) {
var message = evt.data;
alert("Message is received: " + message);
};
ws.onclose = function() {
alert("Connection is closed...");
};
} catch (err) {
alert(err.message);
}
</script>
</head>
<body>
</body>
</html>
As far as I understand, the client should connect to the server, send "Message to send" and the server should reply with "Got it". Instead what the server receives is an http GET request for the client html page and none of the client callbacks are ever fired. What am I missing?
You are missing the very point of WebSocket, its TCP but not raw TCP, to establish a connection the client must send an HTTP request first, then the servers switches protocols to websockets, but remember websocket is not raw TCP, there are custom headers in packets and other.
To save your self some time, try https://github.com/LearnBoost/Socket.IO/ or other websocket libraries https://github.com/joyent/node/wiki/Modules.

Server sent event: Client not receiving response from server

I'm trying to use server sent events so my webpage can have periodic time updates from my server. The issue is that my client is able to interact with my server, however, the response from my server is not making it to my client? Basically, when I open my html file with firefox I know my server gets the request and then it starts sending responses, but nothing shows up on my webpage... Not quite sure what's the issue. Help appreciated!
Here is my client code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<script>
function init(){
if(typeof(EventSource)!=="undefined"){
var source = new EventSource('localhost');
source.onmessage = function(e) {
document.body.innerHTML += e.data + '<br>';
};
}
else{
document.body.innerHTML = "Sorry, your browser does not support server-sent events...";
}
}
</script>
<body onload="init()">
</body>
</html>
Here is my server code (node.js):
var http = require('http');
var sys = require('sys');
var fs = require('fs');
http.createServer(function(req, res) {
if (req.headers.accept && req.headers.accept == 'text/event-stream') {
sendSSE(req, res);
}).listen(80, "127.0.0.1");
function sendSSE(req, res) {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
var id = (new Date()).toLocaleTimeString();
// Sends a SSE every 5 seconds on a single connection.
setInterval(function() {
constructSSE(res, id, (new Date()).toLocaleTimeString());
}, 5000);
}
function constructSSE(res, id, data) {
res.write('id: ' + id + '\n');
res.write("data: " + data + '\n\n');
}
You need to add in
res.end();
somewhere and remove the 'setInterval'. It looks like what you're trying to do, however, is keep the connection alive, in which case you need to change your code significantly. Look into the 'net' module, which is more designed for a "constant on" interactive type of connection.
http://nodejs.org/api/net.html#net_net
The http module is designed for finite, exchange of data, type of requests. You're trying to make it do something it isn't designed to do.
/*jshint node:true */
var http = require('http');
http.createServer(function (req, res) {
'use strict';
console.log('GOOD request recieved');
res.write('hi there');
res.end();
console.log('GOOD end sent');
}).listen(8888);
http.createServer(function (req, res) {
'use strict';
console.log('BAD request received');
res.write('hi there');
console.log('BAD response wrote not ending');
}).listen(8889);
Consider the two servers I have above. If you ping them both with node client code, you will see data come in to both, and should see chunks as they are sent. However, if you try to ping 8889 with a browser, the webpage will never render, because the end event is never sent. Browsers depend on this to know all content has been received. If you're client code is working within a browswer, this may be effecting things. Attempt to use plain NodeJS client code against your server first, and make sure data is getting sent the way you expect it is. Then work on figuring out how the browser is upsetting things. My guess would be that the data gets received by the browser, but it never does anything with it, and sits and waits to distribute it for that 'end' event, the same way in which the 8889 server's webpage never renders... it believes there is more data to wait for.
Sample client code:
var options = {
hostname: '127.0.0.1',
method: 'GET'
};
options.port = 8888;
http.request(options, function (res) {
'use strict';
console.log('GOOD Pinged server');
res.on('data', function (chunk) {
console.log('GOOD data chunk:' + chunk);
});
res.on('end', function () {
console.log('GOOD end event recieved');
});
}).end();
options.port = 8889;
http.request(options, function (res) {
'use strict';
console.log('BAD Pinged server');
res.on('data', function (chunk) {
console.log('BAD data chunk:' + chunk);
});
res.on('end', function () {
console.log('BAD end event recieved');
});
}).end();
The http module in node works fine for Server Sent Events and most demo code for Node SSE uses it. But you do have to be careful about some gotchas.
I got bit by compression being turned on. The solution there is to add res.flush() after the last res.write() of each data message. Since that's an easy fix, I would try that first before rewriting using a different module.

NodeJS sessions, cookies and mysql

I'm trying to build an auth system and I have app.js
var express = require('express')
, MemoryStore = require('express').session.MemoryStore
, app = express();
app.use(express.cookieParser());
app.use(express.session({ secret: 'keyboard cat', store: new MemoryStore({ reapInterval: 60000 * 10 })}));
app.use(app.router);
and the route.index as
var express = require('express')
, mysql = require('mysql')
, crypto = require('crypto')
, app = module.exports = express();
app.get('/*',function(req,res){
var url = req.url.split('/');
if (url[1] == 'favicon.ico')
return;
if (!req.session.user) {
if (url.length == 4 && url[1] == 'login') {
var connection = mysql.createConnection({
host : 'localhost',
user : 'user',
password : 'pass',
});
var result = null;
connection.connect();
connection.query('use database');
var word = url[3];
var password = crypto.createHash('md5').update(word).digest("hex");
connection.query('SELECT id,level FROM users WHERE email = "'+url[2]+'" AND password = "'+password+'"', function(err, rows, fields) {
if (err) throw err;
for (i in rows) {
result = rows[i].level;
}
req.session.user = result;
});
connection.end();
}
}
console.log(req.session.user)
when I access http://mydomain.com/login/user/pass a first time it shows in the last console call but a second time access the cookie is clean
Why do you not just use Express's session handling? if you use the express command line tool as express --sessions it will create the project template with session support. From there you can copy the session lines into your current project. There more information in How do sessions work in Express.js with Node.js? (which this looks like it may be a duplicate of)
As for sanitizing your SQL, you seem to be using the library, which will santitize your inputs for your if you use parameterized queries (ie, ? placeholders).
Final thing, you are using Express wrong (no offence). Express's router will let you split alot of your routes (along with allowing you to configure the favicon. See Unable to Change Favicon with Express.js (second answer).
Using the '/*' route will just catch all GET requests, which greatly limits what the router can do for you.
(continued from comments; putting it here for code blocks)
Now that you have an app with session support, try these two routes:
app.get('/makesession', function (req, res) {
req.session.message = 'Hello world';
res.end('Created session with message : Hello world');
});
app.get('/getsession', function (req, res) {
if (typeof req.session.message == 'undefined') {
res.end('No session');
} else {
res.end('Session message: '+req.session.message);
}
});
If you navigate in your browser to /makesession, it will set a session message and notify you that it did. Now if you navigate to /getsession, it will send you back the session message if it exists, or else it will tell you that the session does not exist.
You need to save your cookie value in the response object:
res.cookie('session', 'user', result);
http://expressjs.com/api.html#res.cookie