Reading data from arduino with nodejs and socketio - javascript

I have this simple code that I'm running in arduino
char inp;
void setup(){
Serial.begin(9600);
}
void loop(){
while(Serial.available()>0){
inp = Serial.read();
Serial.print(inp);
}
Serial.print("--");
delay(200);
}
So it continiously writes "--" and if I send something to arduino it replies with that
Then I have in a js file
var strinInfo = "";
tempSerial.on("data", function(data) {
console.log("data -> " + data);
if (stringInfo.length < 37){
stringInfo += data;
}else{
io.sockets.emit("message", stringInfo);
stringInfo = ""
}
});
That sends via sockets what I got from arduino.
My problem is that, for example, if I send
"thisisanunusuallongandterriblestringofsymbolsblablablablablablabla"
There are missing characters:
---------thisisanunusuallongandterribles,
gofsymbolsblablablablabla--blabla ----,
-------------------------------------,
in this example I'm missing "trin". Is there a way of not losing that characters?
I'm starting with node so my guess is that between the time that it emits the message ... the content from that moment is gone, maybe I'm wrong.

Looking at your code, it could be a couple of things.
You may be sending data before the listener is ready, the above libs below have that solved.
The following line worries me if (stringInfo.length < 37){. If you get successive small packets of data, the packet that puts you over 37 will only print the stringInfo but will not print the data portion.
Libs that connect to Arduino:
[Johnny Five][1]
[Firmata][2]
Both programs interact with Arduinos. Firmata is the low level one with Johnny-Five running on top.

I believe it might be the issue of baud-rate.
If you are using serialport module for serial communication with Arduino than you have to set serialport baud-rate to 9600 (same as receiving side i.e. Arduino).
By default serialport baud rate is 115200.

Related

How to efficiently stream a real-time chart from a local data file

complete noob picking up NodeJS over the last few days here, and I've gotten myself in big trouble, it looks like. I've currently got a working Node JS+Express server instance, running on a Raspberry Pi, acting as a web interface for a local data acquisition script ("the DAQ"). When executed, the script writes out data to a local file on the Pi, in .csv format, writing out in real-time every second.
My Node app is a simple web interface to start (on-click) the data acquisition script, as well as to plot previously acquired data logs, and visualize the actively being collected data in real time. Plotting of old logs was simple, and I wrote a JS function (using Plotly + d3) to read a local csv file via AJAX call, and plot it - using this script as a starting point, but using the logs served by express rather than an external file.
When I went to translate this into a real-time plot, I started out using the setInterval() method to update the graph periodically, based on other examples. After dealing with a few unwanted recursion issues, and adjusting the interval to a more reasonable setting, I eliminated the memory/traffic issues which were crashing the browser after a minute or two, and things are mostly stable.
However, I need help with one thing primarily:
Improving the efficiency of my first attempt approach: This acquisition script absolutely needs to be written to file every second, but considering that a typical run might last 1-2 weeks, the file size being requested on every Interval loop will quickly start to balloon. I'm completely new to Node/Express, so I'm sure there's a much better way of doing the real-time rendering aspect of this - that's the real issue here. Any pointers of a better way to go about doing this would be massively helpful!
Right now, the killDAQ() call issued by the "Stop" button kills the underlying python process writing out the data to disk. Is there a way to hook into using that same button click to also terminate the setInterval() loop updating the graph? There's no need for it to be updated any longer after the data acquisition has been stopped so having the single click do double duty would be ideal. I think that setting up a listener or res/req approach would be an option, but pointers in the right direction would be massively helpful.
(Edit: I solved #2, using global window. variables. It's a hack, but it seems to work:
window.refreshIntervalId = setInterval(foo);
...
clearInterval(window.refreshIntervalId);
)
Thanks for much for the help!
MWE:
html (using Pug as a template engine):
doctype html
html
body.default
.container-fluid
.row
.col-md-5
.row.text-center
.col-md-6
button#start_button(type="button", onclick="makeCallToDAQ()") Start Acquisition
.col-md-6
button#stop_button(type="button", onclick="killDAQ()") Stop Acquisition
.col-md-7
#myDAQDiv(style='width: 980px; height: 500px;')
javascript (start/stop acquisition):
function makeCallToDAQ() {
fetch('/start_daq', {
// call to app to start the acquisition script
})
.then(console.log(dateTime))
.then(function(response) {
console.log(response)
setInterval(function(){ callPlotly(dateTime.concat('.csv')); }, 5000);
});
}
function killDAQ() {
fetch('/stop_daq')
// kills the process
.then(function(response) {
// Use the response sent here
alert('DAQ has stopped!')
})
}
javascript (call to Plotly for plotting):
function callPlotly(filename) {
var csv_filename = filename;
console.log(csv_filename)
function makeplot(csv_filename) {
// Read data via AJAX call and grab header names
var headerNames = [];
d3.csv(csv_filename, function(error, data) {
headerNames = d3.keys(data[0]);
processData(data, headerNames)
});
};
function processData(allRows, headerNames) {
// Plot data from relevant columns
var plotDiv = document.getElementById("plot");
var traces = [{
x: x,
y: y
}];
Plotly.newPlot('myDAQDiv', traces, plotting_options);
};
makeplot(filename);
}
node.js (the actual Node app):
// Start the DAQ
app.use(express.json());
var isDaqRunning = true;
var pythonPID = 0;
const { spawn } = require('child_process')
var process;
app.post('/start_daq', function(req, res) {
isDaqRunning = true;
// Call the python script here.
const process = spawn('python', ['../private/BIC_script.py', arg1, arg2])
pythonPID = process.pid;
process.stdout.on('data', (myData) => {
res.send("Done!")
})
process.stderr.on('data', (myErr) => {
// If anything gets written to stderr, it'll be in the myErr variable
})
res.status(200).send(); //.json(result);
})
// Stop the DAQ
app.get('/stop_daq', function(req, res) {
isDaqRunning = false;
process.on('close', (code, signal) => {
console.log(
`child process terminated due to receipt of signal ${signal}`);
});
// Send SIGTERM to process
process.kill('SIGTERM');
res.status(200).send();
})

Why is Net.Socket.Write() not sending the full string to my TCP client?

EDIT: Im desperate to get this thing done so I can move onto a new project, heres the source: https://github.com/eanlockwood/TalkmonClient
Everything else works fine. The server is well aware of the usernames associated with the clients and it sends information to them accordingly, but the weird thing is the string cuts off after the first variable. Here is the loop for a typical send message:
function SendMessage(msg, client)
{
const clientName = ClientNames.get(client);
let recieverMsg = `${clientName}: ${msg}`;
console.log(recieverMsg);
Clients.forEach(elm => {
if(elm != client)
{
elm.write(recieverMsg);
}
else {
elm.write("You: " + msg);
}
})
}
msg is the chunk.toString() in the socket.on('data') event, again, node picks up what this string means, it debugs fine but in the client (imagine the windows cmd) itll just print the username and go to the next line.
The loop for the client side is pretty simple too,
char buff[4090];
do
{
ZeroMemory(buff, 4090);
int messageRevieved = recv(sock, buff, 4090, 0);
if (messageRevieved > 0)
{
userInput->FreezeInput();
cout << buff << endl;
userInput->UnFreezeInput();
}
} while (0 == 0);
User input is handled in its own class on a seperate thread, again, working just fine.
I think it has to do with a misunderstanding of what socket.write and recv actually do or maybe I just dont understand javascript strings enough. Either way this problem is annoying because its the last step in creating my app
Ive done some extensive tests too, it really just doesnt like the concat strings. Itll print everything up until the first variable, meaning I could have socket.write("hehehehehehe " + variable1 + " kadjgkdgad"); and it would print hehehehehe [variable1 value] and just stop
Tl;dr: The server will write to the sockets up to the first variable in a concat'd string and then stop, its so weird.
EDIT: The dependencies used serverside are Net and dotnet if that makes a difference.
EDIT 2: I found another issue. After sending a few messages the client who sent the messages will stop printing the "you: " part and will only print the message, it will do this server side too but its weird because the receiving clients will still print out who the message is from.

How to Communicate with Web App and C#

I'm attempting to make a Web app that needs to communicate to a program written in C Sharp. But I can't find a good form of communication. What I need is if a user clicks something on the Web app, it will notify the C Sharp program. Also, if an event happens on the C Sharp program, it needs to alert the Web app. Both of these are going to be running on the same machine.
Right now I'm mainly focusing on the C Sharp program just periodically "asking" what the status of the Web app is.
I've tried using POST requests to the Web app and I've had a bit of success with this but I don't know how to essentially store and update a "status" on the Web App. For example, C Sharp program sends a POST/GET request asking for the status, the Web app responds with "nothing has changed" or some sort of status code. I don't know how to keep track of that status.
I've attempted using Web Sockets but I don't think it is going to be possible on the C Sharp side. However, I'm definitely open to suggestions on how this might work.
I've tried using Socket.io with Node.js but I haven't been successful at all. I have never used Node.js before so I did a few examples and I get the very basic elements of it but I cannot set up a complete web socket. Also, I could not get Socket.io to work for me at all.
I've looked into using the ReST architectural style but I'm having a hard time understanding how I would implement it. I'm using mainly AJAX on an Apache server and most of the ReST examples I saw used IIS.
One way I've been successful with this is a horrible workaround. I use 3 files to store contents, status of Web app, and status of C Sharp program. But this requires me constantly fetching files, reading them, writing a new one, and uploading it.
This is as far as I got with a websocket that uses "ws://echo.websocket.org" to simply echo the response. I don't know how to direct the messages to a C Sharp application:
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript">
function WebSocketTest(){
var ws = new WebSocket("ws://echo.websocket.org");
var msg = document.getElementById("message").value;
ws.onopen = function(){
ws.send(msg);
alert("Message Sent: " + msg);
};
ws.onmessage = function (event){
var received_msg = event.data;
var response
if(received_msg == "1"){
response = "Some Response";
alert("Message Received: " + received_msg + "\nResponse: " + response);
}else if(received_msg == "2"){
response = "Some Response";
alert("Message Received: " + received_msg + "\nResponse: " + response);
}else if(received_msg == "3"){
response = "Some Acknowledged Response";
alert("Message Received: " + received_msg + "\nResponse: " + response);
}else{
alert("Message Received: " + received_msg);
response = "Command Not Recognized";
}
//ws.send(event.data);
};
ws.onclose = function(){
alert("Connection is closed...");
};
}
</script>
</head>
<body>
<input type="text" id="message" placeholder="Message to Send"></input>
<div id="sse">
Run WebSocket
</div>
Type in a message to send to an "echo" Web Socket.<br>
Message will be sent, Web Socket will send back the same message. <br>
</body>
</html>
The above example will echo what gets sent and if the response happens to be a 1, 2, or 3. It will also display a custom response. This may not be exactly what I want.
For Clarification:
I would like to have a C Sharp program running in the background. Some event happens that the C Sharp program captures, it will send that event to the Web App which the user will be looking at.
Also, the Web App is running and the user clicks something so the Web App needs to send some message to the C Sharp program to handle it accordingly.
The Web App that I'm speaking of is using a bunch of Javascript/Jquery/AJAX that displays a bunch of controls to the user. The C Sharp program implements these controls to do what they are supposed to do. Let me know if I need to clarify more. A lot of this is obviously very new to me so I apologize.
NOTE: I asked this question a few days ago but I am now elaborating more and including source code. I thought about just editing the previous post but it didn't have a whole lot of insight or attention so I figured it would be better to create a new post. If I should have just edited the previous post just let me know and I will do that from now on. Thanks.

Arduino Webserver Update

I have a small tidbit of code for my webserver on my arduino connected to an ethernet shield:
client.println("<html><head><title>ArduServ</title></head><body>");
client.print("Current Temperature: ");client.println(getTMP());
client.println("<form method=get>Input:<input type=text size=25 name=inp><input type=submit value=submit></form>");
client.println("</body></html>");
Is there a way I can update the temperature using javascript so that I don't have to redraw the page every second? I can just change the temperature?
I personally would not use the Arduino as an HTTP server for a couple of reasons.
Performance - as a micro controller, you have limited resources. Serving all of the headers and content can be expensive if you want the interaction to be real time.
Manageability - as I'm sure you're aware, it's really frustrating having to manage the source of the web page through strings in double quotes on multiple lines like that.
The Solution
I've found that the most effective way to make a web controller interface for an Arduino is to host the page somewhere on your computer locally or even on a server if you have one. Then, make the Arduino a web socket server instead of HTTP server.
This will allow you to easily communicate using the WebSocket class in JavaScript, while not having to worry about the overhead of hosting the web content.
I've used this web socket server implementation for Arduino and it works great.
Here's a basic example based on what you showed us.
Arduino
Assuming ethernet is an EthernetServer, and socket is a WebSocketServer.
// initialize the ethernet and socket server in setup() here ...
void loop(void)
{
EthernetClient client = ethernet.available();
if (client.connected() && socket.handshake(client))
{
while (client.connected())
{
String response;
// add the temperature to the response
response += getTMP();
// send the response to the JavaScript interface
socket.sendData(response);
// update every 250 milliseconds
delay(250);
}
}
// wait to let the client fully disconnect
delay(100);
}
JavaScript
// assuming you have something like <div id="temperature"></div> in the document
var temperature = document.getElementById('temperature');
// whatever IP that was assigned to the EthernetServer
var ip = '192.168.0.99';
var socket = new WebSocket('ws://'+ ip);
socket.onmessage = function(e) {
// update the temperature text
temperature.innerHTML = e.data;
};
You can find more information about JavaScript web sockets here.

How to process streaming HTTP GET data?

Right now, I have a node.js server that's able to stream data on GET request, using the stream API. The GET request is Transfer-encoded set to 'chunked'. The data can be on the order of 10 to 30 MBs. (They are sometimes 3D models)
On the browser side, I wish to be able to process the data as I'm downloading it--I wish to be able to display the data on Canvas as I'm downloading it. So you can see the 3D model appear, face by face, as the data is coming in. I don't need duplex communication, and I don't need a persistent connection. But I do need to process the data as soon as it's downloaded, rather than waiting for the entire file to finish downloading. Then after the browser downloads the data, I can close the connection.
How do I do this?
JQuery ajax only calls back when all the data has been received.
I also looked at portal.js (which was jquery-streaming) and socket.io, but they seem to assume persistent reconnection.
So far, I was able to hack a solution using raw XMLHttpRequest, and making a callback when readyStead >= 2 && status == 200, and keeping track of place last read. However, that keeps all the data downloaded in the raw XMLHttpRequest, which I don't want.
There seems to be a better way to do this, but I'm not sure what it is. Any one have suggestions?
oboe.js is a library for streaming responses in the browser.
However, that keeps all the data downloaded in the raw XMLHttpRequest, which I don't want.
I suspect this may be the case with oboe.js as well and potentially a limitation of XMLHttpRequest itself. Not sure as I haven't directly worked on this type of use case. Curious to see what you find out with your efforts and other answers to this question.
So I found the answer, and it's Server-sent events. It basically enables one-way http-streams that the browser can handle a chunk at a time. It can be a little tricky because some existing stream libs are broken (they don't assume you have \n in your stream, and hence you get partial data), or have little documentation. But it's not hard to roll your own (once you figure it out).
You can define your sse_transform like this:
// file sse_stream.coffee
var Transform = require('stream').Transform;
var util = require('util');
util.inherits(SSEStream, Transform);
function SSEStream(option) {
Transform.call(this, option);
this.id = 0;
this.retry = (option && option.retry) || 0;
}
SSEStream.prototype._transform = function(chunk, encoding, cb) {
var data = chunk.toString();
if (data) {
this.push("id:" + this.id + "\n" +
data.split("\n").map(function (e) {
return "data:" + e
}).join("\n") + "\n\n");
//"retry: " + this.retry);
}
this.id++;
cb();
};
SSEStream.prototype._flush = function(next) {
this.push("event: end\n" + "data: end" + "\n\n");
next();
}
module.exports = SSEStream;
Then on the server side (I was using express), you can do something like this:
sse_stream = require('sse_stream')
app.get '/blob', (req, res, next) ->
sse = new sse_stream()
# It may differ here for you, but this is just a stream source.
blobStream = repo.git.streamcmd("cat-file", { p: true }, [blob.id])
if (req.headers["accept"] is "text/event-stream")
res.type('text/event-stream')
blobStream.on("end", () -> res.removeAllListeners()).stdout
.pipe(
sse.on("end", () -> res.end())
).pipe(res)
else
blobStream.stdout.pipe(res)
Then on the browser side, you can do:
source = new EventSource("/blob")
source.addEventListener('open', (event) ->
console.log "On open..."
, false)
source.addEventListener('message', (event) ->
processData(event.data)
, false)
source.addEventListener('end', (event) ->
console.log "On end"
source.close()
, false)
source.addEventListener('error', (event) ->
console.log "On Error"
if event.currentTarget.readyState == EventSource.CLOSED
console.log "Connection was closed"
source.close()
, false)
Notice that you need to listen for the event 'end', that is sent from the server in the transform stream's _flush() method. Otherwise, EventSource in the browser is just going to request the same file over and over again.
Note that you can use libraries on the server side to generate SSE. On the browser side, you can use portal.js to handle SSE. I just spelt things out, so you can see how things would work.

Categories

Resources