This moduel implements a TokenInterface for CoAP over WebSockets.

As with CoAP-over-TCP, while the transport distinguishes a connection initiator (“WebSocket (and TCP) client”) and a receiver (“WebSocket (and TCP) server”), both sides can take both roles in CoAP (ie. as a CoAP server and a CoAP client). As the WebSocket client can not possibly be connected to (even by the same server – once the connection is closed, it’s gone and even a new one likely has a different port), aiocoap does not allow expressing their addresses in URIs (given they wouldn’t serve their purpose as URLs and don’t provide any stability either). Requests to a CoAP-over-WS client can be made by assigning the remote to an outgoing request.

Port choice

Unlike the other transports, CoAP-over-WS is specified with a privileged port (port 80) as the default port. This is impractical for aiocoap servers for two reasons:

  • Unless explicitly configured, aiocoap is typically run as an unprivileged user (and has no provisions in place to receive a socket by other means than opening it).
  • Where a CoAP-over-WS proxy is run, there is often a “proper” website running on the same port on a full HTTP server. That server is usually capable of forwarding requests, whereas the websockets module used by aiocoap is in no position to either serve websites nor to proxy to an underlying server.

The recommended setup is therefore to run a full web server at port 80, and configure it to proxy incoming requests for WebSockets at /.well-known/coap to aiocoap’s server, which defaults to binding to port 8683.

The port choice of outgoing connections, or the interpretation of the protocol’s default port (ie. the port implied by coap+ws://hostname/) is of course unaffected by this.


Due to a shortcoming of aiocoap’s way of specifying ports to bind to, if a port is explicitly stated to bind to, CoAP-over-WS will bind to that port plus 3000 (resulting in the abovementioned 8683 for 5683). If TLS server keys are given, the TLS server is launched on the next port after the HTTP server (typically 8684).

class, hostinfo)

Bases: tuple


Alias for field number 1


Alias for field number 0

class, connection, loop, log, *, scheme, local_hostinfo=None, remote_hostinfo=None)

Bases: aiocoap.transports.rfc8323common.RFC8323Remote, aiocoap.interfaces.EndpointAddress

scheme = None

Send Release message, (not implemented:) wait for connection to be actually closed by the peer.

Subclasses should extend this to await closing of the connection, especially if they’d get into lock-up states otherwise (was would WebSockets).

class, log, loop)

Bases: aiocoap.interfaces.TokenInterface

classmethod create_transport(tman: aiocoap.interfaces.TokenManager, log, loop, *, client_credentials, server_bind=None, server_context=None)

Return True if the message is recognized to already have a .remote managedy by this TokenInterface, or return True and set a .remote on message if it should (by its unresolved remote or Uri-* options) be routed through this TokenInterface, or return False otherwise.

send_message(message, messageerror_monitor)

Send a message. If it returns a a callable, the caller is asked to call in case it no longer needs the message sent, and to dispose of if it doesn’t intend to any more.

messageerror_monitor is a function that will be called at most once by the token interface: When the underlying layer is indicating that this concrete message could not be processed. This is typically the case for RSTs on from the message layer, and used to cancel observations. Errors that are not likely to be specific to a message (like retransmission timeouts, or ICMP errors) are reported through dispatch_error instead. (While the information which concrete message triggered that might be available, it is not likely to be relevant).

Currently, it is up to the TokenInterface to unset the no_response option in response messages, and to possibly not send them.