Home

Awesome

node-coap

Build Status Coverage Status gitter

node-coap is a client and server library for CoAP modeled after the http module.

NPM

NPM

<a name="intro"></a>

Introduction

What is CoAP?

Constrained Application Protocol (CoAP) is a software protocol intended to be used in very simple electronics devices that allows them to communicate interactively over the Internet. - Wikipedia

This library follows:

It does not parse the protocol but it use CoAP-packet instead.

If you need a command line interface for CoAP, check out coap-cli.

node-coap is an OPEN Open Source Project, see the <a href="#contributing">Contributing</a> section to find out what this means.

The library is tested with LTS versions (currently 12, 14, 16 and 18).

<a name="install"></a>

Installation

$ npm install coap --save

<a name="basic"></a>

Basic Example

The following example opens a UDP server and sends a CoAP message to it:

const coap = require('coap')
const server = coap.createServer()

server.on('request', (req, res) => {
  res.end('Hello ' + req.url.split('/')[1] + '\n')
})

// the default CoAP port is 5683
server.listen(() => {
  const req = coap.request('coap://localhost/Matteo')

  req.on('response', (res) => {
    res.pipe(process.stdout)
    res.on('end', () => {
      process.exit(0)
    })
  })

  req.end()
})

or on IPv6:

const coap = require('coap')
const server = coap.createServer({ type: 'udp6' })

server.on('request', (req, res) => {
  res.end('Hello ' + req.url.split('/')[1] + '\n')
})

// the default CoAP port is 5683
server.listen(() => {
  const req = coap.request('coap://[::1]/Matteo')

  req.on('response', (res) => {
    res.pipe(process.stdout)
    res.on('end', () => {
      process.exit(0)
    })
  })

  req.end()
})

<a name="proxy"></a>

Proxy features

The library now comes with the ability to behave as a COAP proxy for other COAP endpoints. In order to activate the proxy features, create the server with the proxy option activated.

A proxy-enabled service behaves as usual for all requests, except for those coming with the Proxy-Uri option. This requests will be redirected to the URL specified in the option, and the response from this option will, in turn, be redirected to the caller. In this case, the proxy server handler is not called at all (redirection is automatic).

You can find an example of how this mechanism works in examples/proxy.js. This example features one target server that writes all the information it receives along with the origin port and a proxy server. Once the servers are up:

The example shows that the target server sees the last ten requests as coming from the same port (the proxy), while the first ten come from different ports.

<a name="api"></a>

API


<a name="request"></a>

request(requestParams)

Execute a CoAP request. requestParams can be a string or an object. If it is a string, it is parsed using new URL(requestParams). If it is an object:

coap.request() returns an instance of <a href='#outgoing'><code>OutgoingMessage</code></a>. If you need to add a payload, just pipe into it. Otherwise, you must call end to submit the request.

If hostname is a IPv6 address then the payload is sent through a IPv6 UDP socket, dubbed in node.js as 'udp6'.

Event: 'response'

function (response) { }

Emitted when a response is received. response is an instance of <a href='#incoming'><code>IncomingMessage</code></a>.

If the observe flag is specified, the 'response' event will return an instance of <a href='#observeread'><code>ObserveReadStream</code></a>. Which represent the updates coming from the server, according to the observe spec.


<a name="createServer"></a>

createServer([options], [requestListener])

Returns a new CoAP Server object.

The requestListener is a function which is automatically added to the 'request' event.

The constructor can be given an optional options object, containing one of the following options:

Event: 'request'

function (request, response) { }

Emitted each time there is a request. request is an instance of <a href='#incoming'><code>IncomingMessage</code></a> and response is an instance of <a href='#outgoing'><code>OutgoingMessage</code></a>.

If the observe flag is specified, the response variable will return an instance of <a href='#observewrite'><code>ObserveWriteStream</code></a>. Each write(data) to the stream will cause a new observe message sent to the client.

server.listen(port, [address], [callback])

Begin accepting connections on the specified port and hostname. If the hostname is omitted, the server will accept connections directed to any IPv4 or IPv6 address by passing null as the address to the underlining socket.

To listen to a unix socket, supply a filename instead of port and hostname.

A custom socket object can be passed as a port parameter. This custom socket must be an instance of EventEmitter which emits message, error and close events and implements send(msg, offset, length, port, address, callback) function, just like dgram.Socket. In such case, the custom socket must be pre-configured manually, i.e. CoAP server will not bind, add multicast groups or do any other configuration.

This function is asynchronous.

server.close([callback])

Closes the server.

This function is synchronous, but it provides an asynchronous callback for convenience.


<a name="outgoing"></a>

OutgoingMessage

An OutgoingMessage object is returned by coap.request or emitted by the coap.createServer 'response' event. It may be used to access response status, headers and data.

It implements the Writable Stream interface, as well as the following additional properties, methods and events.

message.code

The CoAP code of the message. It is HTTP-compatible, as it can be passed 404.

message.statusCode

(same as message.code)

<a name="setOption"></a>

message.setOption(name, value)

Sets a single option value. All the options are in binary format, except for 'Content-Format', 'Accept', 'Max-Age' and 'ETag'. See <a href='#registerOption'><code>registerOption</code></a> to know how to register more.

Use an array of buffers if you need to send multiple options with the same name.

If you need to pass a custom option, pass a string containing a a number as key and a Buffer as value.

Example:

message.setOption('Content-Format', 'application/json')

or

message.setOption('555', [Buffer.from('abcde'), Buffer.from('ghi')])

setOption is also aliased as setHeader for HTTP API compatibility.

Also, 'Content-Type' is aliased to 'Content-Format' for HTTP compatibility.

Since v0.7.0, this library supports blockwise transfers, you can trigger them by adding a req.setOption('Block2', Buffer.of(0x2)) to the output of request.

And since v0.25.0, this library supports rudimentry type 1 blockwise transfers, you can trigger them by adding a req.setOption('Block1', Buffer.of(0x2)) to the options of request.

(The hex value 0x2 specifies the size of the blocks to transfer with. Use values 0 to 6 for 16 to 1024 byte block sizes respectively.)

See the spec for all the possible options.

message.reset()

Returns a Reset COAP Message to the sender. The RST message will appear as an empty message with code 0.00 and the reset flag set to true to the caller. This action ends the interaction with the caller.

message.writeHead(code, headers)

Functions somewhat like http's writeHead() function. If code is does not match the CoAP code mask of #.##, it is coerced into this mask. headers is an object with keys being the header names, and values being the header values.

message.on('timeout', function(err) { })

Emitted when the request does not receive a response or acknowledgement within a transaction lifetime. Error object with message No reply in XXXs and retransmitTimeout property is provided as a parameter.

message.on('error', function(err) { })

Emitted when an error occurs. This can be due to socket error, confirmable message timeout or any other generic error. Error object is provided, that describes the error.


<a name="incoming"></a>

IncomingMessage

An IncomingMessage object is created by coap.createServer or coap.request and passed as the first argument to the 'request' and 'response' event respectively. It may be used to access response status, headers and data.

It implements the Readable Stream interface, as well as the following additional methods and properties.

message.payload

The full payload of the message, as a Buffer.

message.options

All the CoAP options, as parsed by CoAP-packet.

All the options are in binary format, except for 'Content-Format', 'Accept' and 'ETag'. See <a href='#registerOption'><code>registerOption()</code></a> to know how to register more.

See the spec for all the possible options.

message.headers

All the CoAP options that can be represented in a human-readable format. Currently they are only 'Content-Format', 'Accept' and 'ETag'. See <a href='#registerOption'> to know how to register more.

Also, 'Content-Type' is aliased to 'Content-Format' for HTTP compatibility.

message.code

The CoAP code of the message.

message.method

The method of the message, it might be 'GET', 'POST', 'PUT', 'DELETE' or null. It is null if the CoAP code cannot be parsed into a method, i.e. it is not in the '0.' range.

message.url

The URL of the request, e.g. 'coap://localhost:12345/hello/world?a=b&b=c'.

message.rsinfo

The sender informations, as emitted by the socket. See the dgram docs for details

message.outSocket

Information about the socket used for the communication (address and port).


<a name="observeread"></a>

ObserveReadStream

An ObserveReadStream object is created by coap.request to handle observe requests. It is passed as the first argument to the 'response' event. It may be used to access response status, headers and data as they are sent by the server. Each new observe message from the server is a new 'data' event.

It implements the Readable Stream and IncomingMessage interfaces, as well as the following additional methods, events and properties.

close()

Closes the stream.

message.rsinfo

The sender's information, as emitted by the socket. See the dgram docs for details

message.outSocket

Information about the socket used for the communication (address and port).


<a name="observewrite"></a>

ObserveWriteStream

An ObserveWriteStream object is emitted by the coap.createServer 'response' event as a response object. It may be used to set response status, headers and stream changing data to the client.

Each new write() call is a new message being sent to the client.

It implements the Writable Stream interface, as well as the following additional methods and properties.

Event: 'finish'

Emitted when the client is not sending 'acks' anymore for the sent messages.

reset()

Returns a Reset COAP Message to the sender. The RST message will appear as an empty message with code 0.00 and the reset flag set to true to the caller. This action ends the interaction with the caller.


<a name="registerOption"></a>

coap.registerOption(name, toBinary, toString)

Register a new option to be converted to string and added to the message.headers. toBinary is a function that accept a string and returns a Buffer. toString is a function that accept a Buffer and returns a String.


<a name="ignoreOption"></a>

coap.ignoreOption(name)

Explicitly ignore an option; useful for compatibility with http-based modules.


<a name="registerFormat"></a>

coap.registerFormat(name, value)

Register a new format to be interpreted and sent in CoAP Content-Format option. Each format is identified by a number, see the Content-Format registry.

These are the defaults formats:

Media TypeID
text/plain0
application/cose; cose-type="cose-encrypt0"16
application/cose; cose-type="cose-mac0"17
application/cose; cose-type="cose-sign1"18
application/link-format40
application/xml41
application/octet-stream42
application/exi47
application/json50
application/json-patch+json51
application/merge-patch+json52
application/cbor60
application/cwt61
application/multipart-core62
application/cbor-seq63
application/cose-key101
application/cose-key-set102
application/senml+json110
application/sensml+json111
application/senml+cbor112
application/sensml+cbor113
application/senml-exi114
application/sensml-exi115
application/coap-group+json256
application/dots+cbor271
application/missing-blocks+cbor-seq272
application/pkcs7-mime; smime-type=server-generated-key280
application/pkcs7-mime; smime-type=certs-only281
application/pkcs8284
application/csrattrs285
application/pkcs10286
application/pkix-cert287
application/senml+xml310
application/sensml+xml311
application/senml-etch+json320
application/senml-etch+cbor322
application/td+json432
application/vnd.ocf+cbor10000
application/oscore10001
application/javascript10002
application/vnd.oma.lwm2m+tlv11542
application/vnd.oma.lwm2m+json11543
application/vnd.oma.lwm2m+cbor11544
text/css20000
image/svg+xml30000

<a name="agent"></a>

coap.Agent([opts])

An Agent encapsulate an UDP Socket. It uses a combination of messageId and token to distinguish between the different exchanges. The socket will auto-close itself when no more exchange are in place.

By default, no UDP socket are open, and it is opened on demand to send the messages.

Opts is an optional object with the following optional properties:


<a name="globalAgent"></a>

coap.globalAgent

The default Agent for IPv4.


<a name="globalAgentIPv6"></a>

coap.globalAgentIPv6

The default Agent for IPv6.


<a name="updateTiming"></a>

coap.updateTiming

You can update the CoAP timing settings, take a look at the examples:

const coapTiming = {
  ackTimeout: 0.25,
  ackRandomFactor: 1.0,
  maxRetransmit: 3,
  maxLatency: 2,
  piggybackReplyMs: 10
}
coap.updateTiming(coapTiming)

<a name="defaultTiming"></a>

coap.defaultTiming

Reset the CoAP timings to the default values

<a name="contributing"></a>

Contributing

node-coap is an OPEN Open Source Project. This means that:

Individuals making significant and valuable contributions are given commit-access to the project to contribute as they see fit. This project is more like an open wiki than a standard guarded open source project.

See the CONTRIBUTING.md file for more details.

Contributors

node-coap is only possible due to the excellent work of the following contributors:

<table><tbody> <tr><th align="left">Matteo Collina</th><td><a href="https://github.com/mcollina">GitHub/mcollina</a></td><td><a href="https://twitter.com/matteocollina">Twitter/@matteocollina</a></td></tr> <tr><th align="left">Nguyen Quoc Dinh</th><td><a href="https://github.com/nqd">GitHub/nqd</a></td><td><a href="https://twitter.com/nqdinh">Twitter/@nqdinh</a></td></tr> <tr><th align="left">Daniel Moran Jimenez</th><td><a href="https://github.com/dmoranj">GitHub/dmoranj</a></td><td><a href="https://twitter.com/erzeneca">Twitter/@erzeneca</a></td></tr> <tr><th align="left">Ignacio Martín</th><td><a href="https://github.com/neich">GitHub/neich</a></td><td><a href="https://twitter.com/natxupitxu">Twitter/@natxupitxu</a></td></tr> <tr><th align="left">Christopher Hiller</th><td><a href="https://github.com/boneskull">GitHub/boneskull</a></td><td><a href="https://twitter.com/b0neskull">Twitter/@b0neskull</a></td></tr> </tbody></table>

LICENSE

MIT, see LICENSE.md file.