I'm trying to make a small WiFi control board with the use of an ESP8266 ESP-201 board.
I used the example provided for WebSocket for Arduino, with a little bit of modification to be able to handle JSON messages. This is the code I got to:
/*
* WebSocketClient.ino
*
* Created on: 24.05.2015
*
*/
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WebSocketsClient.h>
#include <ArduinoJson.h>
#include <Hash.h>
ESP8266WiFiMulti WiFiMulti;
WebSocketsClient webSocket;
#define USE_SERIAL Serial
ArduinoJson::StaticJsonBuffer<200> jsonBuffer;
void webSocketEvent(WStype_t type, uint8_t * payload, size_t lenght) {
switch(type) {
case WStype_DISCONNECTED:
USE_SERIAL.printf("[WSc] Disconnected!\n");
break;
case WStype_CONNECTED: {
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
// send message to server when Connected
}
break;
case WStype_TEXT: {
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
String text = String((char *) &payload[0]);
USE_SERIAL.println(text);
JsonObject& root = jsonBuffer.parseObject(text);
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", root["r"]);
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", root["g"]);
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", root["b"]);
}
// send message to server
break;
case WStype_BIN:
USE_SERIAL.printf("[WSc] get binary lenght: %u\n", lenght);
hexdump(payload, lenght);
// send data to server
break;
}
}
void setup() {
USE_SERIAL.begin(115200);
USE_SERIAL.setDebugOutput(true);
USE_SERIAL.println();
USE_SERIAL.println();
USE_SERIAL.println();
for(uint8_t t = 4; t > 0; t--) {
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
USE_SERIAL.flush();
delay(1000);
}
WiFiMulti.addAP("GamersHeavenLow", "nCore4Life");
while(WiFiMulti.run() != WL_CONNECTED) {
delay(100);
}
webSocket.begin("192.168.0.104", 3000);
webSocket.onEvent(webSocketEvent);
}
void loop() {
webSocket.loop();
}
And this is the server side I used to:
var express = require('express');
var app = express();
var url = require('url');
var http = require('http').Server(app);
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({ server: http });
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
app.use(express.static('public'));
wss.on('error', function(error) {
console.log(error);
});
wss.on('connection', function connection(ws) {
var location = url.parse(ws.upgradeReq.url, true);
// you might use location.query.access_token to authenticate or share sessions
// or ws.upgradeReq.headers.cookie (see http://stackoverflow.com/a/16395220/151312)
console.log('connected');
ws.on('message', function incoming(message) {
console.log(message);
wss.clients.forEach(function each(client) {
client.send(JSON.stringify(message));
});
});
//ws.send('something');
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
Before I started to work with the JSON encoding it was working for a while, but now it's not. I get the following error:
[SETUP] BOOT WAIT 4...
scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 5 (10)
add 0
aid 2
cnt
connected with GamersHeavenLow, channel 6
dhcp client start...
ip:192.168.0.101,mask:255.255.255.0,gw:192.168.0.1
[SETUP] BOOT WAIT 3...
[SETUP] BOOT WAIT 2...
[SETUP] BOOT WAIT 1...
[WS-Client] connect ws...
[WS-Client] connection to 192.168.0.104:3000 Faild
[WS-Client] client disconnected.
[WSc] Disconnected!
[WS-Client] connect ws...
[WS-Client] connection to 192.168.0.104:3000 Faild
[WS-Client] client disconnected.
[WSc] Disconnected!
I believed it must have been the JSON decoding, so I reverted back to the default example, but I still get the same message, connection failed.
So I tried to use the echo websocket server, with which the Arduino code started working.
So I figured out it must be a server side issue, so I tested my node.js websocket server with a pure WebSocket client, but that is also working without a problem.
So basically I have two separate sets of code, which are running in isolation from one another without a problem, but they don't want to play along together.
Any idea what might be causing this?
WebSocket server used: https://github.com/websockets/ws
WebSocket client used on ardruino: https://github.com/Links2004/arduinoWebSockets
You need to use the WS module instead of the socket.io.
Related
I am using the following code to simulate a modbus slave device:
const modbus = require('jsmodbus')
const SerialPort = require('serialport')
const options = {
baudRate: 115200
}
const socket = new SerialPort("COM4", options)
const server = new modbus.server.RTU(socket)
server.on('connect', function (client) {
console.log("in connect")
console.log(client);
});
server.on('connection', function (client) {
console.log("in connection")
console.log(client);
});
server.on('readHoldingRegisters', function (adr, len) {
console.log("in readHoldingRegisters")
console.log("adr: " + adr);
console.log("len: " + len);
});
The code above does actually simulate a device. The master I have set up can see a slave device when I run this code. The problem is that I can't seem to get the server functions to reach their console.log sections.
I have two theories.
First, my slave device uses the jsmodbus library to simulate a server and my master device uses modbus-serial to communicate. Could this cause a problem?
My second theory is that the code I have above is running all at once and doesn't look around or stay open to see future communications. How would I solve this?
I am open to new theories as well. My goal is eventually to pass modbus data back to the master through the server.on commands.
Edit
I know for sure there is data coming in if I read the data on the serial port directly:
socket.on('readable', function () {
console.log('Data:', socket.read()) //prints incoming buffer data
});
I still am not getting data through the server commands.
I am struggling quite a while now to get a solid, long-term connection to a bluetooth barcode scanner from Inateck using node.js. The process is running in the background (linux, no input-focus) that's why I configured the scanner as a SPP device.
The connection is basically working as long as the scanner doesn't automatically switch off to save power, which is after about 5 minutes.
My first approach was to use the bluetooth-serial-port package. It discovers the scanner, reads the barcodes but when the scanner switches off, I don't know how to re-connect. I added an interval timer to check the connection and try to connect again if isOpen() returns false (which works once). When I press the button on the scanner it switches back on and I can re-connect but after a view seconds isOpen() returns false even if the connection is established, and I don't get any further readings. Here is my code:
var btSerial = new (require('bluetooth-serial-port')).BluetoothSerialPort();
var btInterval = null;
btSerial.on('found', function (address, name) {
btSerial.findSerialPortChannel(address, function (channel) {
if (address === '00:06:11:68:15:81') {
btSerial.connect(address, channel, function () {
console.log('connected to ' + address);
btInterval = setInterval(function () {
if (!btSerial.isOpen()) {
btSerial.close();
clearInterval(btInterval);
console.log('lost connection - try to reconnect');
btSerial.inquire();
}
}, 5000);
}, function () {
console.log('cannot connect to ' + address);
});
}
}, function () {
console.log('found nothing');
});
});
btSerial.on('finished', function () {
console.log('finished');
});
btSerial.on('data', function (buffer) {
console.log(buffer.toString('utf-8'));
});
btSerial.inquire();
The output looks like this:
finished
connected to 00:06:11:68:15:81
found nothing
... scanning works ...
lost connection - try to reconnect
finished
connected to 00:06:11:68:15:81
... scanning works ...
lost connection - try to reconnect
finished
... that's it - no more scans ...
^C
An other idea was to use nodes fs() an read directly from '/dev/rfcomm0'.
scanner = fs.createReadStream('/dev/rfcomm0', {bufferSize: 1});
scanner.on('open', function () {
logger.info('Scanner connected');
});
scanner.on('end', function () {
logger.info('End of data stream');
});
scanner.on('close', function () {
logger.info('Scanner disconnected');
});
scanner.on('error', function (error) {
logger.error('Scanner error');
});
scanner.on('data', function (chunk) {
logger.info(chunk.toString('ascii', 0, 13));
}
});
});
Connecting is done by the OS automatically when reading from the device and I do receive the codes via on('data',..). But I do have the same problem when the scanner switches off after a while. I do receive the on('close',..) event but reconnecting using fs.createReadStream() again doesn't work any more.
Maybe someone of you already had to deal which such a problem and can give me a hint how to handle this. I appreciate every suggestion.
Thanks,
Max
That's not the way I wanted to go for but a bash script to launch my node app when the scanner is available, does the job:
#!/bin/bash
echo "Press CTRL+C to stop..."
while :
do
if hcitool scan | grep -q "00:06:11:68:15:81"; then
# BT scanner found
node .
fi
sleep 1
done
I have a Node app running on AWS Elastic Beanstalk (so Node running behind Nginx). I am running socket IO with redis as the memory store and have Node running clustered using the cluster module. Generally everything works great but every now and then I get a user trying to connect that throws an undefined error on the connection.remoteAddress. My code looks like this for the connections:
if (cluster.isMaster) {
/*
------------------------------------------------------------------------------------
This stores our workers. We need to keep them to be able to reference
them based on source IP address. It's also useful for auto-restart
We also setup a message listener to every worker in order to blast AND FILTER
socket io updates to all nodes.
------------------------------------------------------------------------------------
*/
var workers = [];
var messageRelay = function(msg) {
for(var i = 0; i < workers.length; i++) {
workers[i].send(msg);
}
};
var spawn = function(i) {
workers[i] = cluster.fork();
console.log("Hello from worker %s",workers[i].process.pid);
workers[i].on('message', messageRelay);
/*
----------------------------------------
Restart worker if it gets destroyed
----------------------------------------
*/
workers[i].on('disconnect', function(worker) {
console.log('Worker disconnected');
});
workers[i].on('exit', function(worker, code, signal) {
console.log('respawning worker', i);
spawn(i);
});
};
for (var i = 0; i < cpuCount; i++) {
spawn(i);
}
/*
--------------------------------------------------------------------------------------------
Helper function for getting a worker index based on IP address (supports IPv4 AND IPv6)
This is a hot path so it should be really fast. The way it works
is by converting the IP address to a number by removing the dots (for IPv4) and removing
the :: for IPv6, then compressing it to the number of slots we have.
Compared against "real" hashing (from the sticky-session code) and
"real" IP number conversion, this function is on par in terms of
worker index distribution only much faster.
--------------------------------------------------------------------------------------------
*/
var workerIndex = function (ip, len) {
var _ip = ip.split(/['.'|':']/),
arr = [];
for (el in _ip) {
if (_ip[el] == '') {
arr.push(0);
}
else {
arr.push(parseInt(_ip[el], 16));
}
}
return Number(arr.join('')) % len;
}
/*
------------------------------------------------------------------------------------
Create the outside facing server listening on our port.
------------------------------------------------------------------------------------
*/
var server = net.createServer({ pauseOnConnect: true }, function(connection) {
/*
------------------------------------------------------------------------------------
We received a connection and need to pass it to the appropriate
worker. Get the worker for this connection's source IP and pass
it the connection.
------------------------------------------------------------------------------------
*/
if(connection.remoteAddress === undefined) {
console.log("BLEH: %o ", connection.remoteAddress);
return;
}
else {
var worker = workers[workerIndex(connection.remoteAddress, cpuCount)];
worker.send('sticky-session:connection', connection);
}
}).listen(port, function() {
console.log("Spun up worker %s", process.pid);
console.log('Server listening on *:' + port);
});
}
else {
var sio = require('socket.io');
var redis = require('socket.io-redis');
var ioEvents = require(__base + 'lib/ioEvents');
var app = new express();
/*
------------------------------------------------------------------------------------
Note we don't use a port here because the master listens on it for us.
------------------------------------------------------------------------------------
*/
var server = app.listen(0, 'localhost'),
io = sio(server);
/*
----------------------------------------------------------------------------------------------
Using Redis as the store instead of memory. This allows us to blast socket updates
to all processes (unfiltered). For example, we can do io.sockets.emit("message")
and it will be distributed to all node processes.
We cannot filter these messages to specific socket connections or specific configurations
(e.g. updateSquares(socket)), in order to do that we must blast an update to all workers
and let each process filter the request individually.
----------------------------------------------------------------------------------------------
*/
io.adapter(redis({host:'localhost', port: portRedis}));
/*
------------------------------------------------------------------------------------
Setup the socket listeners
------------------------------------------------------------------------------------
*/
ioEvents.incoming(io);
/*
------------------------------------------------------------------------------------
Listen to master for worker process updates
------------------------------------------------------------------------------------
*/
process.on('message', function(message, connection) {
/*
------------------------------------------------------------------------------------
Listen for special updates to all nodes
------------------------------------------------------------------------------------
*/
if(message.squareUpdate) {
console.log("worker %s received message %o", process.pid, message.squareUpdate);
ioEvents.squaresForceUpdate(message.squareUpdate);
}
/*
------------------------------------------------------------------------------------
If it's not a special message, then check to make sure it's just a sticky-session
Otherwise, just bail, no need to do anything else
------------------------------------------------------------------------------------
*/
if (message !== 'sticky-session:connection') {
return;
}
/*
------------------------------------------------------------------------------------
| Emulate a connection event on the server by emitting the
| event with the connection the master sent us.
------------------------------------------------------------------------------------
*/
server.emit('connection', connection);
connection.resume();
});
So the problem lies in the section above with the "BLEH" log. For some reason, remoteAddress is undefined...but only SOMETIMES. Most of the connections look just fine, but randomly I'll get a user trying to connect that throws that error. I'd like to understand what is going on here. I've read that I cannot do IP stuff when there is a proxy involved (something between Node and the User)...but 98% of the time, the connections to workers are fine and everything works as expected. Any help here is really appreciated.
Ok, I have an express-powered API where I also have socket.io running to receive/send realtime events...all works just dandy. I need to cluster my app. I set everything up based on the below code. I spin up workers, they get connections and everything works, except the fact that now I can't "blast" to all socket.io connections. Here is the setup (taken from this):
var express = require('express'),
cluster = require('cluster'),
net = require('net'),
sio = require('socket.io'),
sio_redis = require('socket.io-redis');
var port = 3000,
num_processes = require('os').cpus().length;
if (cluster.isMaster) {
// This stores our workers. We need to keep them to be able to reference
// them based on source IP address. It's also useful for auto-restart,
// for example.
var workers = [];
// Helper function for spawning worker at index 'i'.
var spawn = function(i) {
workers[i] = cluster.fork();
// Optional: Restart worker on exit
workers[i].on('exit', function(worker, code, signal) {
console.log('respawning worker', i);
spawn(i);
});
};
// Spawn workers.
for (var i = 0; i < num_processes; i++) {
spawn(i);
}
// Helper function for getting a worker index based on IP address.
// This is a hot path so it should be really fast. The way it works
// is by converting the IP address to a number by removing the dots,
// then compressing it to the number of slots we have.
//
// Compared against "real" hashing (from the sticky-session code) and
// "real" IP number conversion, this function is on par in terms of
// worker index distribution only much faster.
var workerIndex = function (ip, len) {
var _ip = ip.split(/['.'|':']/),
arr = [];
for (el in _ip) {
if (_ip[el] == '') {
arr.push(0);
}
else {
arr.push(parseInt(_ip[el], 16));
}
}
return Number(arr.join('')) % len;
}
// Create the outside facing server listening on our port.
var server = net.createServer({ pauseOnConnect: true }, function(connection) {
// We received a connection and need to pass it to the appropriate
// worker. Get the worker for this connection's source IP and pass
// it the connection.
var worker = workers[worker_index(connection.remoteAddress, num_processes)];
worker.send('sticky-session:connection', connection);
}).listen(port);
} else {
// Note we don't use a port here because the master listens on it for us.
var app = new express();
// Here you might use middleware, attach routes, etc.
// Don't expose our internal server to the outside.
var server = app.listen(0, 'localhost'),
io = sio(server);
// Tell Socket.IO to use the redis adapter. By default, the redis
// server is assumed to be on localhost:6379. You don't have to
// specify them explicitly unless you want to change them.
io.adapter(sio_redis({ host: 'localhost', port: 6379 }));
// Here you might use Socket.IO middleware for authorization etc.
// Listen to messages sent from the master. Ignore everything else.
process.on('message', function(message, connection) {
if (message !== 'sticky-session:connection') {
return;
}
// Emulate a connection event on the server by emitting the
// event with the connection the master sent us.
server.emit('connection', connection);
connection.resume();
});
}
So I connect from various machines to test concurrency, workers do their thing and all is good, but when I get an IO connection, I'm logging the TOTAL "connected" count and it's always 1 per instance. I need a way to say
allClusterForks.emit(stuff)
I get the connection on the correct worker pid, but "ALL CONNECTIONS" always returns 1.
io.on('connection', function(socket) {
console.log('Connected to worker %s', process.pid);
console.log("Adapter ROOMS %s ", io.sockets.adapter.rooms);
console.log("Adapter SIDS %s ", io.sockets.adapter.sids);
console.log("SOCKETS CONNECTED %s ", Object.keys(io.sockets.connected).length);
});
I can see the subscribe/unsubscribe coming in using Redis MONITOR
1454701383.188231 [0 127.0.0.1:63150] "subscribe" "socket.io#/#gXJscUUuVQGzsYJfAAAA#"
1454701419.130100 [0 127.0.0.1:63167] "subscribe" "socket.io#/#geYSvYSd5zASi7egAAAA#"
1454701433.842727 [0 127.0.0.1:63167] "unsubscribe" "socket.io#/#geYSvYSd5zASi7egAAAA#"
1454701444.630427 [0 127.0.0.1:63150] "unsubscribe" "socket.io#/#gXJscUUuVQGzsYJfAAAA#"
These are connections from 2 different machines, I would expect by using the socket io redis adapter that these subscriptions would be coming in on the same redis connection, but they are different.
Am I just totally missing something? There's a surprising lack of documentation/articles out there for this that aren't either completely outdated/wrong/ambiguous.
EDIT:
Node v5.3.0
Redis v3.0.6
Socket.io v1.3.7
So if anyone comes across this, I figured out that actually "looking" at the counts of connected sockets across processes is not a thing, but broadcasting or emitting to them is. So I've basically just been "testing" for no reason. All works as expected. I WILL be rewriting the socket.io-redis adapter to allow checking counts across processes.
There was a pull request a few years ago to implement support for what I was trying to do. https://github.com/socketio/socket.io-redis/pull/15 and I might try cleaning that up and re-submitting.
Im working on a project with an Arduino and Ethernet Shield.
I would like to execute a php script (residing on my server) in the loop.
#include <SPI.h>
#include <Ethernet.h>
// MAC address from Ethernet shield sticker under board
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,1,77); // IP address, may need to change depending on network
EthernetServer server(80); // create a server at port 80
String HTTP_req; // stores the HTTP request
void setup()
{
Ethernet.begin(mac, ip); // initialize Ethernet device
server.begin(); // start to listen for clients
Serial.begin(9600); // for diagnostics
}
void loop()
{
EthernetClient client = server.available(); // try to get client
if (client) { // got client?
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) { // client data available to read
char c = client.read(); // read 1 byte (character) from client
HTTP_req += c; // save the HTTP request 1 char at a time
Serial.print("connected");
client.println("GET http://domain.com/arduino/scripts/script_motion_detection_driveway.php HTTP/1.0");
client.println();
} // end if (client.available())
} // end while (client.connected())
delay(1); // give the web browser time to receive the data
client.stop(); // close the connection
} // end if (client)
}
When I run the code and load the page, instead of executing the script it just prints the line:
GET http://domain.com/arduino/scripts/script_motion_detection_driveway.php HTTP/1.0
over and over again...
The reason its in the loop as opposed to setup is because eventually the GET request will be placed inside an if statement to test a condition.
What do I need to change to execute the script?
You should check this example: http://www.arduino.cc/en/Tutorial/WebClient
You want to execute a GET request without telling the client to connect to the server at the port 80.
if (client.connect(server, 80)) {
Then you make your http request
// Make a HTTP request:
client.println("GET /search?q=arduino HTTP/1.1");
client.println("Host: www.google.com");
client.println("Connection: close");
client.println();
Then you try to read the request
if (client.available()) {
char c = client.read();
Serial.print(c);
}
By putting these parts together in a better way than your script above, you will successfully get the output of your php script.