Internet (HTTP/TCP/UDP/etc)
To use the internet in Espruino you need an internet connection. If you're using Espruino under Linux (for example Raspberry Pi or OpenWRT) then you're sorted and can use the examples below directly, otherwise you'll need a module to connect to the internet. Currently your choices are:
- EspressIf ESP8266 WiFi Module
- TI CC3000 WiFi Module
- WIZnet W5500 Wired Ethernet Module
- SIMCom SIM900 GSM/GPRS Module
You'll need to follow the instructions on those pages first in order to get connected to the net.
Basic internet functionality is handled using the http
, net
and tls
libraries.
Contents
Client
HTTP clients are like Web browsers - they request a webpage from (or submit information to) a web server.
For a simple HTTP client just use http.get
. Note that as the data from the webpage is sent in packets, you must register a handler to deal with each bit of data as it arrives.
The example below will just output the contents of the Espruino website:
var http = require("http");
http.get("https://www.espruino.com", function(res) {
res.on('data', function(data) {
console.log(data);
});
});
You can also handle the close
event so that you can process with the contents of the webpage in one go - be careful you don't run out of RAM for larger webpages though!
require("http").get("https://www.espruino.com", function(res) {
var contents = "";
res.on('data', function(data) { contents += data; });
res.on('close', function() { console.log(contents); });
});
HTTP POST
You can perform HTTP POST using http.request
with method
set to POST
.
function postJSON(postURL, data, callback) {
content = JSON.stringify(data);
var options = url.parse(postURL);
options.method = 'POST';
options.headers = {
"Content-Type":"application/json",
"Content-Length":content.length
};
var req = require("http").request(options, function(res) {
var d = "";
res.on('data', function(data) { d+= data; });
res.on('close', function(data) { callback(d); });
});
req.on('error', function(e) {
callback();
});
req.end(content);
}
postJSON("https://www.example.com", {test:42}, function(d) {
console.log("Response: "+d);
});
Handling Errors
http.get
returns an instance of httpCRq
which will emit an error
event if there are problems connecting.
This means you can trap connection errors with something like the following:
require("http").get("https://192.168.12.34", function(res) {
var contents = "";
res.on('data', function(data) { contents += data; });
res.on('close', function() { console.log(contents); });
}).on('error', function(e) {
console.log("ERROR", e);
});
Server
HTTP servers are pretty easy. Just use http.createServer
, and then use the listen method to specify which port to listen on. The following example will just write 'Hello World' in your web browser if you connect to https://your_device:8080
your_device
will probably be an IP address. Consult the instructions for the module you're using, but you can usually use either eth.getIP()
or wlan.getIP()
to find out what your IP address is.
function pageRequest(req, res) {
res.writeHead(200);
res.end("Hello World");
}
require("http").createServer(pageRequest).listen(8080); // port 8080
Note that we're using port 8080
in these examples, because it works when running Espruino on Linux/Raspberry Pi (without superuser priviledges). If you're using a microcontroller you could just use port 80, which means that you can just connect to https://your_device
.
Pages
By itself this isn't too useful - but a simple way to control things from the webserver is to look at which webpage is requested. In the example here a simple webpage is displayed showing whether the button is on or off, and containing two links - labelled on and off.
When clicked, they request a webpage with the argument ?led=1
or ?led=0
, and the server detects this and turns LED1 on or off to match. url.parse
converts the webpage's arguments into an easy to use form (see below).
function onPageRequest(req, res) {
var a = url.parse(req.url, true);
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<html><body>');
res.write('<p>Pin is '+(BTN.read()?'on':'off')+'</p>');
res.write('<a href="?led=1">on</a><br/><a href="?led=0">off</a>');
res.end('</body></html>');
if (a.query && "led" in a.query)
digitalWrite(LED1, a.query["led"]);
}
require("http").createServer(onPageRequest).listen(8080);
We'd recommend that you use url.parse
to work out more information about the HTTP request (such as the arguments). For instance the following:
function onPageRequest(req, res) {
var a = url.parse(req.url, true);
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(JSON.stringify(a));
}
require("http").createServer(onPageRequest).listen(8080);
Will return:
// https://espruino:8080/
{"method":"GET","host":"","path":"/","pathname":"/","search":null,"port":80,"query":null}
// https://espruino:8080/hello/world
{"method":"GET","host":"","path":"/hello/world","pathname":"/hello/world","search":null,"port":80,"query":null}
// https://espruino:8080/hello?a=b&c=d&e
{"method":"GET","host":"","path":"/hello?a=b&c=d&e","pathname":"/hello","search":"?a=b&c=d&e","port":80,"query":{"a":"b","c":"d","e":""}}
You can easily use this to serve up different webpages:
function onPageRequest(req, res) {
var a = url.parse(req.url, true);
if (a.pathname=="/") {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end("Index Page");
} else if (a.pathname=="/hello") {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end("Hello World");
} else {
res.writeHead(404, {'Content-Type': 'text/plain'});
res.end("404: Page "+a.pathname+" not found");
}
}
require("http").createServer(onPageRequest).listen(8080);
However for real use cases you'll probably want to use Forms and HTTP POST requests, and there's an example of doing that here
Transferring files
You may want to serve up files from the SD card. The most obvious route would be to do something like this:
function onPageRequest(req, res) {
var a = url.parse(req.url, true);
var contents = require("fs").readFileSync(a.pathname);
if (contents !== undefined) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(contents);
} else {
res.writeHead(404, {'Content-Type': 'text/plain'});
res.end("404: Page "+a.pathname+" not found");
}
}
require("http").createServer(onPageRequest).listen(8080);
However there's a problem with this - the file is loaded into memory first, so if it's too big to go into RAM then you won't be able to serve it up. In fact, to serve a file up, you have to be able to load it into memory and then add it to the output buffer - meaning it will have to fit into memory twice over.
Instead, we'd suggest you use 'pipe' from the streaming file API:
function onPageRequest(req, res) {
var a = url.parse(req.url, true);
var f = E.openFile(a.pathname, "r");
if (f !== undefined) {
res.writeHead(200, {'Content-Type': 'text/plain'});
f.pipe(res); // streams the file to the HTTP response
} else {
res.writeHead(404, {'Content-Type': 'text/plain'});
res.end("404: Page "+a.pathname+" not found");
}
}
require("http").createServer(onPageRequest).listen(8080);
This loads the file a section at a time, and even closes it and the HTTP connection once sending is complete.
Note: by default .pipe
will use a relatively small chunk size (the amount of data read and written in one go). Replacing f.pipe(res)
with f.pipe(res, {chunkSize:512});
will drastically increase file transfer speeds as it better matches the block size of SD cards.
Transferring large amounts of data
In a similar way, you may have problems if you're trying to send a lot of data. For instance, you may have a 10,000 byte buffer of data and you want to send it as text.
It's possble that in text form this could take 40,000 bytes (eg. 100,101,102,103,...
), which wouldn't fit into memory.
Instead, you can send the data a chunk at at time, using the HTTP response's drain
event (which is called when the output buffer is empty).
var history = new Uint8Array(10000);
// ...
function onPageRequest(req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
var n = 0;
res.on('drain',function() {
for (var i=0;i<10;i++)
res.write(history[n++]+",");
if (n>=history.length) res.end(" ];");
});
res.write("var data = [");
}
require('http').createServer(onPageRequest).listen(8080);
Sockets
Socket support is handled in a similar way to HTTP, you just use the net
module instead:
For a server:
var server = require("net").createServer(function(c) {
// A new client as connected
c.write("Hello");
c.on('data', function(data) {
console.log(">"+JSON.stringify(data));
});
c.end();
});
server.listen(1234);
Or for a client:
var client = require("net").connect({host: "my.url.com", port: 1234}, function() {
console.log('client connected');
client.write("Hello");
client.on('data', function(data) {
console.log(">"+JSON.stringify(data));
});
client.on('end', function() {
console.log('client disconnected');
});
});
HTTPS
The only boards currently supporting this are the Espruino Pico and WiFi. To use HTTPS simply use it in the URL of any normal HTTP request:
require("http").get("https://www.google.com", function(res) {
res.on('data', function(data) { /* ... */ });
});
To specify keys and certificates, you can use an options object - see require('tls').connect(...)
TLS
The only boards currently supporting this are the Espruino Pico and WiFi. Just use it as follows:
require("tls").connect("my.url.com:1234", function(c) {
c.write("Hello");
c.on('data', function(data) { /* ... */ });
});
See require('tls').connect(...)
for more information.
UDP / Datagram
Most Espruino devices also include UDP support which is modelled around the
Node.js dgram
API.
See Espruino's dram
reference pages
Server (Listener)
var port = 41234;
let dgram = require('dgram');
let srv = dgram.createSocket('udp4');
srv = srv.bind(port, function() {
// server now listening
srv.on('message', function(msg, info) {
// message received
console.log("<"+JSON.stringify(msg));
console.log("<"+JSON.stringify(info));
// you can then 'reply' if needed
srv.send('a reply', info.port, info.address);
});
});
// srv.close(); to force close
Client
let client = dgram.createSocket('udp4');
client.on('message', function(msg, info) {
// message received (only called after first '.send' is used)
console.log(">"+JSON.stringify(msg));
console.log(">"+JSON.stringify(info));
});
client.send('a message', port, 'servername');
// client.close(); to force close
Related Pages
Projects using an Internet Connection
This page is auto-generated from GitHub. If you see any mistakes or have suggestions, please let us know.