Raspberry Pi: send bluetooth readings to local server - bluetooth

I am new to Raspberry Pi developing and I am involved in a project in which we need to take Bluetooth readings sent from different sensors (e.g. temperature sensors, wearable health sensors, etc.) previously paired with our Pi, and send them to a server using Pi as a gateway.
How can I access the port receiving the Bluetooth readings? From there on I suppose it's as simple as writing a script that takes the important information, like device ID and the measurement value, places them inside a formatted message and sends it to the server, but again I need advice.
Any help, even providing links to forums or similar sites, will be very appreciated.
UPDATE:
I am now able to read from every handle in the BLE device and parse the data into a JSON file using a bash script. However, I don't know how to tell Node that I need to update the information every 5 seconds. Here's the code I'm using:
// required modules
var http = require('http');
var fs = require('fs');
var exec = require('child_process').exec;
// for executing bash/shell scripts
function execute(command, callback){
exec(command, function(error, stdout, stderr){ callback(stdout); });
};
// executes script that updates JSON file with new readings
module.exports.getJSONFile = function(callback){
execute("./Scripts/BLEreadingsJSON.sh");
};
// creates HTTP server
http.createServer(function(request, response){
response.writeHead(200,{
'Content-Type': 'text/json' });
setInterval(function(){
var contents = fs.readFile('Scripts/nodeJS/readings.json', function(err, contents){
response.write(contents);
response.end();
});
}, 5*1000);
}).listen(8080); // listen for connections on this port
console.log('Listening to port 8080...');
When I execute this I get the following error:
pi#raspberrypi ~/Scripts $ node nodeJS/sendFileToServer.js
Listening to port 8080...
http.js:851
throw new TypeError('first argument must be a string or Buffer');
^
TypeError: first argument must be a string or Buffer
at ServerResponse.OutgoingMessage.write (http.js:851:11)
at /home/pi/Scripts/nodeJS/sendFileToServer.js:22:13
at fs.js:207:20
at Object.oncomplete (fs.js:107:15)
I suppose this happens because it is trying to access the file before it has been created. How can I do this using a callback?

I got it to work! For those still interested, I ended up using socket.io. I have a script that updates the data with new BLE readings. This node.js code listens for those updates and sends the file to the client:
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var fs = require('fs')
app.get('/', function(req, res){
var index = "index.html";
res.sendFile(index, {root: "absolute_path_to_index"});
});
var text;
fs.readFile('absolute_path_to_file', function(err, data){
text = data;
});
io.on('connection', function(socket){
console.log("User connected");
socket.emit('news', text);
socket.on('disconnect', function(){
console.log("User disconnected");
});
// this line waits for changes in the file and uploads the new data
fs.watchFile('absolute_path_to_file', function(curr, prev){
fs.readFile('absolute_path_to_file', function(err, data){
socket.emit('news', data.toString());
});
});
});
http.listen(4321, function(){
console.log("Listening on port 4321...");
});

Related

socket.io communication between nodejs scripts

I'm trying to setup some socket.io communications, the communication between my server (app.js)(runs on a raspberry pi) and a website(public/index.html) works fine. Now I want to expand it so when my app.js receives a call from index.html it emits it further to another node.js script(bed.js) that will run on another raspberry pi. I tried to use the npm module socket.io-client, but this can only receive apparently
!edit! problem has narrowed down to the setrgb part, there it won't emit.
!edit 2! when i receive setRGB, i emit setRGBclient, but that can only be received in bed.js, not in index.html, there lays my problem, i need to share the connections or force it to another connection, no clue how i fix it though
APP.JS:
let http = require('http').createServer(handler); //require http server, and create server with function handler()
let fs = require('fs'); //require filesystem module
let io = require('socket.io')(http) //require socket.io module and pass the http object (server)
let delay = require('delay');
console.log('Define each color from RGB Strip light.');
http.listen(8080); //listen to port 8080
function handler (req, res) { //create server
fs.readFile(__dirname + '/public/index.html', function(err, data) { //read file index.html in public folder
if (err) {
res.writeHead(404, {'Content-Type': 'text/html'}); //display 404 on error
return res.end("404 Not Found");
}
res.writeHead(200, {'Content-Type': 'text/html'}); //write HTML
res.write(data); //write data from index.html
return res.end();
});
}
io.sockets.on('connection', function (socket) {// WebSocket Connection
socket.on("test", function(){
console.log("sampletext");
});
socket.on("setRGB", function(data){
socket.emit("setRGBClient", data);
console.log(data);
console.log("test");
});
});
bed.js:
let socket = require('socket.io-client')('http://localhost:8080');
let lightstate = false;
let stayOff = false;
let fadeState = false;
console.log("check");
socket.emit("test");
socket.on("setRGBClient" ,function(data) {
console.log(data);
});
I can just broadcast setRGBClient.
socket.broadcast.emit("setRGBClient", data);
I guess this is a learning exercise. Otherwise I’d caution against socket.io for such applications.
However I can only see the subscription for ‘setRGB’ not the emit-part.

Node server cannot open specified port

I am trying to write a program that allows me to communicate with a device using the serial port. To do so, I am using the following code :
var express = require('express');
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var SerialPort = require("serialport");
var port = new SerialPort("/dev/ttyS1");
app.use(express.static(__dirname+"/../.."));
app.use(express.static(__dirname+"/../../../bower_components/"));
io.on('connection', function(socket) {
console.log('new connection');
socket.on('message', function (message) {
//console.log('Position : ' + message); //envoi port ... à la place
//port.on('open', function() {
port.write(message, function(err) {
if (err) {
return console.log('Error on write: ', err.message);
}
});
//});
});
});
server.listen(8080, function() {
console.log('server up and running at 8080 port');
});
However, the issue here is that the port never seems to open, but the value we are supposed to send is still printed in the console,and the /dev/tty (which represents the console) is opened, but the /dev/ttyS1 do not get opened. The following screenshot is obtained after executing
sudo strace -e open,write node server.js
According to the documentation, the port is supposed to open automatically when we instantiate the SerialPort object.
So, are there any issues in my code or is there any better way to do this ?

See client download progress from server

Currently, I have a lot of linux based clients downloading firmware updates from my webserver.
After the client has successfully downloaded the firmware file, my server needs to execute a few scripts, which logs in to the client and performs some tasks.
Is there a way for a node server to keep track of the clients download progress, so I can execute the needed scripts once the file has been downloaded?
Ok so I will try.
If you serve your Firmware as static files through Apache/Nginx and direct url call. You don't get the progress inside your NodeJS script.
If you serve your files via stream inside a express controller you can listen to the progress. Look at this answer here https://stackoverflow.com/a/42273080/3168392
You will have to use a socket connection to make sure the node server gets update from the client of the progress of the file being downloaded.
Something like this
CLIENT_CODE
var socket = io('http://localhost');
socket.on('connect', function(){});
socket.on('data_reciving', parts.pop(),function(percentage){
if(parse_data(percentage) === 100){
client.socket.emit('downloadCompleted', {fileName:'test'});
}else{
//do nothing
}
});
SERVER_CODE:
sockets.on('connection', function (socket) {
//listen to the event from client
socket.on('downloadCompleted', function (data) {
connect_to_client();
do_some_operation();
socket.emit('ALLDONE',{some_data});
});
});
I guess this helps ,you can use this post for reference.
If you just want to run some code when a download has finished, you can use on-finished:
const onFinished = require('on-finished');
app.use((req, res, next) => {
onFinished(res, (err, res) => {
...log some data, perform some housekeeping, etc...
});
next();
});
As is, it will attach a "finished" listener to all responses, which is probably not what you want. Since this is plain Express middleware, you can attach it to specific routes instead (but how depends on how exactly the files are being served).
I found some code that seems to fit my needs.
With the code below, I can detect both the progress of a user's download from the server-side, and fire an event once the file transfer completes.
var http = require("http");
var fs = require("fs");
var filename = "./large-file";
var serv = http.createServer(function (req, res) {
var sent = 0;
var lastChunkSize = 0;
var stat = fs.statSync(filename);
res.setHeader('Content-disposition', 'attachment; filename=large-file.iso');
res.setHeader('Accept-Ranges', 'bytes');
res.setHeader('Keep-Alive', 'timeout=5, max=100');
res.writeHeader(200, {"Content-Length": stat.size});
var fReadStream = fs.createReadStream(filename, { highWaterMark: 128 * 1024 });
fReadStream.on('data', function (chunk) {
if(!res.write(chunk)){
fReadStream.pause();
lastChunkSize = chunk.length;
console.log('Sent', sent, 'of', stat.size);
}
});
fReadStream.on('end', function () {
console.log('Transfer complete.');
res.end();
});
res.on("drain", function () {
sent += lastChunkSize;
fReadStream.resume();
});
});
serv.listen(3001);

Can't connect to socket after emit

I am working on project that involves real time temperatures and have a device sending temps via get that is routed through the server and emitted to the socket. Then I want the server to connect to the original socket and emit the data to a new one that is being read by my client.
Here is my app.js
var express = require('express'),
app = express(),
server = require('http').createServer(app),
io = require('socket.io').listen(server);
server.listen(8080);
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
});
app.route('/:temp')
.get(function (req, res){
var temp = req.params.temp;
res.end(temp);
io.sockets.on('connection', function(socket){
socket.emit('send temp', temp);
});
});
io.sockets.on('connection', function(socket){
socket.on('send temp', function(data){
console.log('connected to send temp');//this never shows in the console
io.sockets.emit('new temp', data);
});
});
The route code in app.js works fine. When I hit localhost:3000/test and change the client to connect to 'send temp' (rather then 'new temp') 'test' is output.
Here is the relevant section of my client
var socket = io.connect();
var $temp = $('#temp');
socket.on('new temp', function(data){
$temp.html("Temp: " + "<br/>"+data);
});
I am running node version 4.1.2, socket 1.3.7 and express 4.10.8.
I am wondering why I cannot connect to the original socket a second time. Or that may not even be my problem. I have studied the many 'chat' tutorials and searched for others using trying to do what I want to without any success.
Ultimately what I am trying to have happen is have a client hit /:temp over and over with a real-time reading and then have other clients get that data in real-time.
This is all still a little new to me so any help is appreciated.
Your code example registers a message handler on the server for the 'send temp' message. The client registers a message handler for the 'new temp' message.
The two (client and server) are then sitting there in a stalemate waiting for someone to first send a message, but (per the code you've disclosed) nobody ever does.
I don't really understand what the intent is for your code, but I see several issues.
First off, you do not want to install a listener for the connection event inside this code:
app.route('/:temp')
.get(function (req, res){
var temp = req.params.temp;
res.end(temp);
io.sockets.on('connection', function(socket){
socket.emit('send temp', temp);
});
});
Why would you only start listening for a connection event when you get a particular route handler. And, why add yet another event handler every time that route is hit. This code is just completely wrong. I don't know what you thought you were trying to achieve with it, but it's not the way to do things.
Second off, this code is waiting for the client to send a 'send temp' message and when it gets one, it attempts to broadcast that to all clients. But, the part of your client you disclose never sends a 'send temp' message.
io.sockets.on('connection', function(socket){
socket.on('send temp', function(data){
console.log('connected to send temp');//this never shows in the console
io.sockets.emit('new temp', data);
});
});
Third off, please describe exactly what you're trying to accomplish in words so we can better know what code to recommend in order to do that.
EDIT
Now that you've described the actual problem here:
Ultimately what I am trying to have happen is have a client hit /:temp
over and over with a real-time reading and then have other clients get
that data in real-time.
It is a little easier to recommend a solution:
On the server:
var express = require('express'),
app = express(),
server = require('http').createServer(app),
io = require('socket.io').listen(server);
server.listen(8080);
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
});
app.get('/:temp', function (req, res) {
var temp = req.params.temp;
res.end(temp);
// send this temperature to all connected clients
io.emit('new temp', temp);
});
On the client:
var socket = io.connect();
var $temp = $('#temp');
socket.on('new temp', function(data){
$temp.html("Temp: " + "<br/>"+data);
});

connect cmd line socket server via nodejs socket.io

I have a node.js server communicating to a client web page, sending it message. This is working great based on the many tutorials and searching stack overflow :)
Where I am having an issue is when I attempt to startup a separate socket connection to a 3rd party cmd line executable instance runs as a socket server. The 3rd party executable does not adhere to the socket.io namespace/room type of events, so I read that socket.io-events may help where instead of:
socket.on('some key', function(){/**do stuff*/}); I could:
eventRouter.on('*', function(){/*do stuff*/});
For this communication, I am assuming I need to use socket.io-client on the node.js side in order to talk to the cmd executable, but I am getting exceptions trying to do a socket2.use(router); where socket2 is my socket.io-client and router is the socket.io-events object.
All runs on localhost, node to web page is port 8001 and node.js to executable is on port 8002. Please pardon the code, for I have been trying to get this to work for a few days and is a bit ugly now.
The cmd executable to execute and its arguments I have coming from the web page which works. I am able to start the exe. The EXE expects a ACK on each message sent, thus why you see the code emitting it back.
I have a interval where I set and update an element on the web page. I have another element that I set messages (msg).
var http = require('http');
var url = require('url');
var fs = require('fs');
var server;
server = http.createServer(function(req, res){
// your normal server code
var path = url.parse(req.url).pathname;
switch (path){
case '/':
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<h1>Hello! Try the Test page </h1>');
res.end();
break;
case '/socket.html':
fs.readFile(__dirname + path, function(err, data){
if (err){
return send404(res);
}
res.writeHead(200, {'Content-Type': path == 'json.js' ? 'text/javascript' : 'text/html'});
res.write(data, 'utf8');
res.end();
});
break;
default: send404(res);
}
}),
send404 = function(res){
res.writeHead(404);
res.write('404');
res.end();
};
server.listen(8001);
var str = "ack0";
var bytes = [];
for (var i = 0; i < str.length; ++i) {
bytes.push(str.charCodeAt(i));
}
// use socket.io
var io = require('socket.io').listen(server);
// define interactions with client
io.sockets.on('connection', function(socket){
//send data to client
setInterval(function(){
socket.emit('date', {'date': new Date()});
}, 1000);
//recieve client data
socket.on('client_data', function(data){
var spawn = require('child_process').spawn;
console.log('pre-spawned');
spawn(data.cmd, data.args, {});
setTimeout(function() {
console.log('hello world!');
}, 1000);
var aptIO = require('socket.io-client');
var router = require('socket.io-events')();
var socket2 = aptIO.connect('localhost:8002', {reconnect: true});
router.on('connection', function(s){
//send data to client
console.log('apt');
router.on('*', function(sock, args, next){
var name = args.shift(), msg = args.shift();
console.log(name + " " + JSON.stringify(msg));
sock.emit(bytes);
io.sockets.emit('msg', {'msg': JSON.stringify(msg)})
next();
});
s.emit(bytes);
});
console.log('spawned');
// getting runtime exceptions here...have tried various things...
socket2.use(router);
});
});
With the help from JGreenwell, I was able to resolve me issue.
I ended up having the node server communicate to the client html page via socket.io connection for messages. The node server would launch the cmd line executable providing it the port to connect to which is different from the socket.io port used.
Once started, the executable would communicate with the server via the net module. The server would just pass the information on to the socket.io connection. the js in the html page knows how to parse the message in order to increment the progress bar and list the messages in a text area control.
I took it even further by having the messages be broadcast-ed to multiple clients on the socket.io connection.

Resources