micropython client from raspberry pi pico cannot connect to local host - node.js

I have a node.js server in which I am trying to send data in real time from my raspberry pi pico w over sockets.
My Simple Server is setup as follows:
const express = require("express")
const app = express();
const http = require("http");
const { Server } = require("socket.io");
const cors = require("cors")
const server = http.createServer(app)
const io = new Server(server, {
cors: {
origin: "*",
}
})
io.on("connection", (socket) => {
console.log('User Connected: ${socket.id}');
})
app.get('/', function(req, res, next) {
res.send("Hello world");
});
server.listen(80, () => {
console.log("Server is running")
})
The code I am running on the client side on my Raspberry Pi Pico W is as follows:
import time
import socket
import network
ssid = '<name>'
password = '<password>'
# Just making our internet connection
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
# Wait for connect or fail
max_wait = 10
while max_wait > 0:
if wlan.status() < 0 or wlan.status() >= 3:
break
max_wait -= 1
print('waiting for connection...')
time.sleep(1)
# Handle connection error
if wlan.status() != 3:
raise RuntimeError('network connection failed')
else:
print('connected')
status = wlan.ifconfig()
print(wlan.ifconfig())
c = socket.socket()
c.connect(('http://127.0.0.1/',80))
print('Connected')
After ensuring the server is working just fine (i setup a react client and was able to transfer information), I am still unsure why my micropython-based client on my microcontroller cannot setup a socket. I keep getting the error:
Traceback (most recent call last):
File "<stdin>", line 32, in <module>
OSError: [Errno 103] ECONNABORTED
If someone could guide me on potential solutions that would be extremely helpful. Thanks!

The python socket library is for the lower level TCP connection to 127.0.0.1 on port 80.
HTTP and WebSockets are a layer on top the raw socket and require a specific client or socket code that understands each protocol.
Socket.io is another layer on top of those providing a way to negotiate a connection via HTTP or WS and the subsequent message formatting.
Plain sockets
A simple node socket server looks like:
const net = require('node:net')
const server = net.createServer(function(socket) {
socket.write('Echo server\r\n')
socket.pipe(socket)
})
server.listen(1111, '127.0.0.1')
Which you connect with:
c.connect(('127.0.0.1',1111))
HTTP
HTTP is likely the easiest route. I think urequests is bundled most of the time, or writing the HTTP request to the raw socket is not overly hard to implement yourself.
Using HTTP will have some overhead compared to sockets/web sockets, if you are streaming large amounts of data.
WebSockets
On the python side you would need a client like micropython-uasyncio-websockets (not sure if this is useful, just searched). This would require a server like the ws library provides on the node server side.
Socket.io
It might be hard to find an up to date socket.io library that works with micropython.

Related

How can I access create-react-app over external network

I have created a simple create-react-app which opens a websocket connection to an equally simple websocket echo server in python.
Everything works fine on my local network, however I'd also like to try to connect from outside my local network. To accomplish this I've forwarded port 3000 on my router to the computer running the create-react-app application and tested by connecting a separate computer through the hotspot on my smartphone to the ip address of my router at port 3000.
This fails without properly connecting to the python websocket echo server.
I can connect from an external network to the create-react-app (the default logo is displayed and the page is displayed properly) however the issue is when using the react app to connect to the python echo server.
Any ideas on where to go from here?
Here is the relevant code in App.js:
// Address and port of the python websocket server
const URL = 'ws://localhost:8765'
class EchoWebsocket extends Component {
ws = new WebSocket(URL);
componentDidMount() {
// Callback function when connected to websocket server
this.ws.onopen = () => {
// on connecting, do nothing but log it to the console
console.log('Opening new websocket #' + URL);
console.log('connected')
console.log('Websocket readyState = ', this.ws.readyState);
}
console.log('Websocket readyState = ', this.ws.readyState);
// Callback function when connection to websocket server is closed
this.ws.onclose = () => {
console.log('disconnected')
console.log('Websocket readyState = ', this.ws.readyState);
// automatically try to reconnect on connection loss
console.log('Opening new websocket #' + URL);
}
// Callback function to handle websocket error
this.ws.onerror = event => {
console.log("WebSocket Error: " , event);
}
}
render() {
return(
<div></div>
);
}
}
I also reference <EchoWebsocket /> later in App.js
Here is the python websocket echo server:
#!/usr/bin/env python
import asyncio
import websockets
async def echo(websocket, path):
async for message in websocket:
await websocket.send(message)
asyncio.get_event_loop().run_until_complete(
websockets.serve(echo, '', 8765))
asyncio.get_event_loop().run_forever()
Changing the ip address in App.js to the ip address of the router and forwarding port 8765 in the router to the computer running the websocket echo server allows this code to work both on the local network and from an external network.

Node js with express return connection closed before receiving a handshake response

I have a socket running in nodejs and using this socket in html page this is working fine and some times I'm receiving the error on developer console as like
failed: Connection closed before receiving a handshake response. In this time my update not getting reflect on the user screen. Actually whenever the changes updated in admin screen I written the login in laravel to store this values into the redis and I have used the laravel event broadcast and in node js socket.io read the redis value change and push the values into the user screens.
I have code in laravel as like,
Laravel Controller,
public function updatecommoditygroup(Request $request)
{
$request_data = array();
parse_str($request, $request_data);
app('redis')->set("ssahaitrdcommoditydata", json_encode($request_data['commodity']));
event(new SSAHAITRDCommodityUpdates($request_data['commodity']));
}
In this above controller when the api call receives just store the values into this redis key and broadcast the event.
In my event class,
public $updatedata;
public function __construct($updatedata)
{
$this->updatedata = $updatedata;
}
public function broadcastOn()
{
return ['ssahaitrdupdatecommodity'];
}
Finally I have written my socket.io file as like below,
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var Redis = require('ioredis');
var redis = new Redis({ port: 6379 } );
redis.subscribe('ssahaitrdupdatecommodity', function(err, count) {
});
io.on('connection', function(socket) {
console.log('A client connected');
});
redis.on('pmessage', function(subscribed, channel, data) {
data = JSON.parse(data);
io.emit(channel + ':' + data.event, data.data);
});
redis.on('message', function(channel, message) {
message = JSON.parse(message);
io.emit(channel + ':' + message.event, message.data);
});
http.listen(3001, function(){
console.log('Listening on Port 3001');
});
When I have update the data from admin I'm passing to laravel controller, and controller will store the received data into redis database and pass to event broadcast.And event broadcast pass the values to socket server and socket server push the data whenever the redis key get change to client page.
In client page I have written the code as like below,
<script src="../assets/js/socket.io.js"></script>
var socket = io('http://ip:3001/');
socket.on("novnathupdatecommodity:App\\Events\\NOVNATHCommodityUpdates", function(data){
//received data processing in client
});
Everything working fine in most of the time and some times issue facing like
**VM35846 socket.io.js:7 WebSocket connection to 'ws://host:3001/socket.io/?EIO=3&transport=websocket&sid=p8EsriJGGCemaon3ASuh' failed: Connection closed before receiving a handshake response**
By this issue user page not getting update with new data. Could you please anyone help me to solve this issue and give the best solution for this issue.
I think this is because your socket connection timeout.
new io({
path:,
serveClient:,
orgins:,
pingTimeout:,
pingInterval:
});
The above is the socket configuration. If you are not configuring socket sometime it behaves strangely. I do not know the core reason, but i too have faced similar issues that implementing the socket configuration solved it.
Socket.io Server
Similar configuration should be done on the client side. There is an option of timeout in client side
Socket.io Client
For example.
Say this is your front-end code
You connect to the socket server using the following command:
io('http://ip:3001', { path: '/demo/socket' });
In your server side when creating the connection:
const io = require("socket.io");
const socket = new io({
path: "/demo/socket",
serveClient: false /*whether to serve the client files (true/false)*/,
orgins: "*" /*Supports cross orgine i.e) it helps to work in different browser*/,
pingTimeout: 6000 /*how many ms the connection needs to be opened before we receive a ping from client i.e) If the client/ front end doesnt send a ping to the server for x amount of ms the connection will be closed in the server end for that specific client*/,
pingInterval: 6000 /* how many ms before sending a new ping packet */
});
socket.listen(http);
Note:
To avoid complication start you http server first and then start you sockets.
There are other options available, but the above are the most common ones.
I am just describing what i see in the socket.io document available in github.socket_config. Hope this helps

Socket.IO connection error

I've an application in node.js with socket.io. Everything was running completely fine, but suddenly the browser started to send this error.
failed: Error in connection
establishment:net::ERR_TUNNEL_CONNECTION_FAILED
I didn't make any code change.
The protocol used by socket is ws:// and when I try to use this url in browser
'ws://highgarden-nodejs-91180.sae1.nitrousbox.com/socket.io/?EIO=3&transport=websocket&sid=T9Unec8KbWw-GAL8AAAF'
Chrome returns this error:
Failed to load resource: net::ERR_DISALLOWED_URL_SCHEME
This is a part of the socket setup code:
server.js:
var app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server);
var port = process.env.PORT || 3000
*------------------------------------------*
// routes ===
var routes = require('./config/routes.js');
var sock = {}
routes(app, passport, sock);
io.sockets.on('connection', sock.update);
// launch ===
server.listen(port);
Thanks advance.
Hi the exception ERR_TUNNEL_CONNECTION_FAILED happens when a tunnel connection through the proxy could not be established. And the ERR_DISALLOWED_URL_SCHEME happens when the scheme of the URL is disallowed.
May you need use it behind the proxy!
Chrome 45.0.2454.101 m says the page has been disabled or moved on the server.

nodejs serialport module or bluetooth-serial-port module, which one?

I have a couple of nodejs examples for serial communication. One example is using the serialport module (below). I have a paired bluetooth device which is set up as rfcomm0. I can communicate with it over the command line with echo data > /dev/rfcomm0 and receive a response, so it seems to work. The problem is that it doesn't work through nodejs. The example below throws a "could not load bindings file" error when I do nodejs SerialToJson.js /dev/rfcomm0. The alternative is to use the Bluetooth-serial-port module instead but that too cannot be installed through npm because a compatible version cannot be found for the version of node I'm using. I have an idea of how to troubleshoot each problem but I don't know which to pursue, can the serialport module be used with rfcomm (serial port emulation) or is the Bluetooth-serial-port module better suited?
/*
SerialToJson.js
a node.js app to read serial strings, convert them to
JSON objects, and send them to webSocket clients
requires:
* node.js (http://nodejs.org/)
* express.js (http://expressjs.com/)
* socket.io (http://socket.io/#how-to-use)
* serialport.js (https://github.com/voodootikigod/node-serialport)
To call it type:
node SerialToJSON.js portname
where portname is the path to the serial port you want to open.
created 1 Nov 2012
modified 7 Nov 2012
by Tom Igoe
*/
var serialport = require("serialport"), // include the serialport library
SerialPort = serialport.SerialPort, // make a local instance of serial
app = require('express')(), // start Express framework
server = require('http').createServer(app), // start an HTTP server
io = require('socket.io').listen(server); // filter the server using socket.io
var portName = process.argv[2]; // third word of the command line should be serial port name
console.log("opening serial port: " + portName); // print out the port you're listening on
server.listen(8080); // listen for incoming requests on the server
console.log("Listening for new clients on port 8080");
var connected = false;
// open the serial port. Change the name to the name of your port, just like in Processing and Arduino:
var myPort = new SerialPort(portName, {
// look for return and newline at the end of each data packet:
parser: serialport.parsers.readline("\r\n")
});
// respond to web GET requests with the index.html page:
app.get('/', function (request, response) {
response.sendfile(__dirname + '/index.html');
});
// listen for new socket.io connections:
io.sockets.on('connection', function (socket) {
// if the client connects:
if (!connected) {
// clear out any old data from the serial bufffer:
myPort.flush();
// send a byte to the serial port to ask for data:
myPort.write('c');
console.log('user connected');
connected = true;
}
// if the client disconnects:
socket.on('disconnect', function () {
myPort.write('x');
console.log('user disconnected');
connected = false;
});
// listen for new serial data:
myPort.on('data', function (data) {
// Convert the string into a JSON object:
var serialData = JSON.parse(data);
// for debugging, you should see this in the terminal window:
console.log(data);
// send a serial event to the web client with the data:
socket.emit('serialEvent', serialData);
});
});
Good to know it's working. Serialport module works for me too.
With module serialport, you need another module to connect with the bluetooth device, or you need to manually connect with rfcomm in terminal.
The big difference in functionality is that bluetooth-serial-port doesn't require you to connect with rfcomm. This module can scan bluetooth devices and connect with them. After you connect, it has the same functionality as serialport.
So if your application/module only needs to connect with bluetooth devices and you want scanning functionality, it's worth to at least try bluetooth-serial-port.
There are a few examples in the npm module/readme, so it won't take much time to just test it.
EDIT:
There is a new version released, which is very stable! :D
https://npmjs.org/package/bluetooth-serial-port

Is it possible to enable tcp, http and websocket all using the same port?

I am trying to enable tcp, http and websocket.io communication on the same port. I started out with the tcp server (part above //// line), it worked. Then I ran the echo server example found on websocket.io (part below //// line), it also worked. But when I try to merge them together, tcp doesn't work anymore.
SO, is it possible to enable tcp, http and websockets all using the same port? Or do I have to listen on another port for tcp connections?
var net = require('net');
var http = require('http');
var wsio = require('websocket.io');
var conn = [];
var server = net.createServer(function(client) {//'connection' listener
var info = {
remote : client.remoteAddress + ':' + client.remotePort
};
var i = conn.push(info) - 1;
console.log('[conn] ' + conn[i].remote);
client.on('end', function() {
console.log('[disc] ' + conn[i].remote);
});
client.on('data', function(msg) {
console.log('[data] ' + conn[i].remote + ' ' + msg.toString());
});
client.write('hello\r\n');
});
server.listen(8080);
///////////////////////////////////////////////////////////
var hs = http.createServer(function(req, res) {
res.writeHead(200, {
'Content-Type' : 'text/html'
});
res.end(['<script>', "var ws = new WebSocket('ws://127.0.0.1:8080');", 'ws.onmessage = function (data) { ws.send(data); };', '</script>'].join(''));
});
hs.listen(server);
var ws = wsio.attach(hs);
var i = 0, last;
ws.on('connection', function(client) {
var id = ++i, last
console.log('Client %d connected', id);
function ping() {
client.send('ping!');
if (last)
console.log('Latency for client %d: %d ', id, Date.now() - last);
last = Date.now();
};
ping();
client.on('message', ping);
});
You can have multiple different protocols handled by the same port but there are some caveats:
There must be some way for the server to detect (or negotiate) the protocol that the client wishes to speak. You can think of separate ports as the normal way of detecting the protocol the client wishes to speak.
Only one server process can be actually listening on the port. This server might only serve the purpose of detecting the type of protocol and then forwarding to multiple other servers, but each port is owned by a single server process.
You can't support multiple protocols where the server speaks first (because there is no way to detect the protocol of the client). You can support a single server-first protocol with multiple client-first protocols (by adding a short delay after accept to see if the client will send data), but that's a bit wonky.
An explicit design goal of the WebSocket protocol was to allow WebSocket and HTTP protocols to share the same server port. The initial WebSocket handshake is an HTTP compatible upgrade request.
The websockify server/bridge is an example of a server that can speak 5 different protocols on the same port: HTTP, HTTPS (encrypted HTTP), WS (WebSockets), WSS (encrypted WebSockets), and Flash policy response. The server peeks at the first character of the incoming request to determine if it is TLS encrypted (HTTPS, or WSS) or whether it begins with "<" (Flash policy request). If it is a Flash policy request, then it reads the request, responds and closes the connection. Otherwise, it reads the HTTP handshake (either encrypted or not) and the Connection and Upgrade headers determine whether it is a WebSocket request or a plain HTTP request.
Disclaimer: I made websockify
Short answer - NO, you can't have different TCP/HTTP/Websocket servers running on the same port.
Longish answer -
Both websockets and HTTP work on top of TCP. So you can think of a http server or websocket server as a custom TCP server (with some state mgmt and protocol specific encoding/decoding). It is not possible to have multiple sockets bind to the same port/protocol pair on a machine and so the first one will win and the following ones will get socket bind exceptions.
nginx allows you to run http and websocket on the same port, and it forwards to the correct appliaction:
https://medium.com/localhost-run/using-nginx-to-host-websockets-and-http-on-the-same-domain-port-d9beefbfa95d

Resources