aiocoap module

The aiocoap package is a library that implements CoAP, the Constrained Application Protocol.

If you are reading this through the Python documentation, be aware that there is additional documentation available online and in the source code’s doc directory.

Module contents

This root module re-exports the most commonly used classes in aiocoap: Context, Message as well as all commonly used numeric constants from numbers; see their respective documentation entries.

The presence of Message and Context in the root module is stable.

class aiocoap.Type

Bases: enum.IntEnum

An enumeration.

CON = 0
NON = 1
ACK = 2
RST = 3
class aiocoap.Code

Bases: aiocoap.util.ExtensibleIntEnum

Value for the CoAP “Code” field.

As the number range for the code values is separated, the rough meaning of a code can be determined using the is_request(), is_response() and is_successful() methods.

EMPTY = <Code 0 "EMPTY">
GET = <Request Code 1 "GET">
POST = <Request Code 2 "POST">
PUT = <Request Code 3 "PUT">
DELETE = <Request Code 4 "DELETE">
FETCH = <Request Code 5 "FETCH">
PATCH = <Request Code 6 "PATCH">
iPATCH = <Request Code 7 "iPATCH">
CREATED = <Successful Response Code 65 "2.01 Created">
DELETED = <Successful Response Code 66 "2.02 Deleted">
VALID = <Successful Response Code 67 "2.03 Valid">
CHANGED = <Successful Response Code 68 "2.04 Changed">
CONTENT = <Successful Response Code 69 "2.05 Content">
CONTINUE = <Successful Response Code 95 "2.31 Continue">
BAD_REQUEST = <Response Code 128 "4.00 Bad Request">
UNAUTHORIZED = <Response Code 129 "4.01 Unauthorized">
BAD_OPTION = <Response Code 130 "4.02 Bad Option">
FORBIDDEN = <Response Code 131 "4.03 Forbidden">
NOT_FOUND = <Response Code 132 "4.04 Not Found">
METHOD_NOT_ALLOWED = <Response Code 133 "4.05 Method Not Allowed">
NOT_ACCEPTABLE = <Response Code 134 "4.06 Not Acceptable">
REQUEST_ENTITY_INCOMPLETE = <Response Code 136 "4.08 Request Entity Incomplete">
CONFLICT = <Response Code 137 "4.09 Conflict">
PRECONDITION_FAILED = <Response Code 140 "4.12 Precondition Failed">
REQUEST_ENTITY_TOO_LARGE = <Response Code 141 "4.13 Request Entity Too Large">
UNSUPPORTED_CONTENT_FORMAT = <Response Code 143 "4.15 Unsupported Media Type">
UNSUPPORTED_MEDIA_TYPE = <Response Code 143 "4.15 Unsupported Media Type">
UNPROCESSABLE_ENTITY = <Response Code 150 "4.22 Unprocessable Entity">
TOO_MANY_REQUESTS = <Response Code 157 "4.29 Too Many Requests">
INTERNAL_SERVER_ERROR = <Response Code 160 "5.00 Internal Server Error">
NOT_IMPLEMENTED = <Response Code 161 "5.01 Not Implemented">
BAD_GATEWAY = <Response Code 162 "5.02 Bad Gateway">
SERVICE_UNAVAILABLE = <Response Code 163 "5.03 Service Unavailable">
GATEWAY_TIMEOUT = <Response Code 164 "5.04 Gateway Timeout">
PROXYING_NOT_SUPPORTED = <Response Code 165 "5.05 Proxying Not Supported">
HOP_LIMIT_REACHED = <Response Code 168 "5.08 Hop Limit Reached">
CSM = <Code 225 "7.01 Csm">
PING = <Code 226 "7.02 Ping">
PONG = <Code 227 "7.03 Pong">
RELEASE = <Code 228 "7.04 Release">
ABORT = <Code 229 "7.05 Abort">
is_request()

True if the code is in the request code range

is_response()

True if the code is in the response code range

is_signalling()
is_successful()

True if the code is in the successful subrange of the response code range

can_have_payload()

True if a message with that code can carry a payload. This is not checked for strictly, but used as an indicator.

class_

The class of a code (distinguishing whether it’s successful, a request or a response error or more).

>>> Code.CONTENT
<Successful Response Code 69 "2.05 Content">
>>> Code.CONTENT.class_
2
>>> Code.BAD_GATEWAY
<Response Code 162 "5.02 Bad Gateway">
>>> Code.BAD_GATEWAY.class_
5
dotted

The numeric value three-decimal-digits (c.dd) form

name_printable

The name of the code in human-readable form

name

The constant name of the code (equals name_printable readable in all-caps and with underscores)

class aiocoap.OptionNumber

Bases: aiocoap.util.ExtensibleIntEnum

A CoAP option number.

As the option number contains information on whether the option is critical, and whether it is safe-to-forward, those properties can be queried using the is_* group of methods.

Note that whether an option may be repeated or not does not only depend on the option, but also on the context, and is thus handled in the Options object instead.

IF_MATCH = <OptionNumber 1 "IF_MATCH">
URI_HOST = <OptionNumber 3 "URI_HOST">
ETAG = <OptionNumber 4 "ETAG">
IF_NONE_MATCH = <OptionNumber 5 "IF_NONE_MATCH">
OBSERVE = <OptionNumber 6 "OBSERVE">
URI_PORT = <OptionNumber 7 "URI_PORT">
LOCATION_PATH = <OptionNumber 8 "LOCATION_PATH">
OSCORE = <OptionNumber 9 "OBJECT_SECURITY">
OBJECT_SECURITY = <OptionNumber 9 "OBJECT_SECURITY">
URI_PATH = <OptionNumber 11 "URI_PATH">
CONTENT_FORMAT = <OptionNumber 12 "CONTENT_FORMAT">
MAX_AGE = <OptionNumber 14 "MAX_AGE">
URI_QUERY = <OptionNumber 15 "URI_QUERY">
HOP_LIMIT = <OptionNumber 16 "HOP_LIMIT">
ACCEPT = <OptionNumber 17 "ACCEPT">
Q_BLOCK1 = <OptionNumber 19 "Q_BLOCK1">
LOCATION_QUERY = <OptionNumber 20 "LOCATION_QUERY">
EDHOC = <OptionNumber 21 "EDHOC">
BLOCK2 = <OptionNumber 23 "BLOCK2">
BLOCK1 = <OptionNumber 27 "BLOCK1">
SIZE2 = <OptionNumber 28 "SIZE2">
Q_BLOCK2 = <OptionNumber 31 "Q_BLOCK2">
PROXY_URI = <OptionNumber 35 "PROXY_URI">
PROXY_SCHEME = <OptionNumber 39 "PROXY_SCHEME">
SIZE1 = <OptionNumber 60 "SIZE1">
ECHO = <OptionNumber 252 "ECHO">
NO_RESPONSE = <OptionNumber 258 "NO_RESPONSE">
REQUEST_TAG = <OptionNumber 292 "REQUEST_TAG">
REQUEST_HASH = <OptionNumber 548 "REQUEST_HASH">
is_critical()
is_elective()
is_unsafe()
is_safetoforward()
is_nocachekey()
is_cachekey()
format
create_option(decode=None, value=None)

Return an Option element of the appropriate class from this option number.

An initial value may be set using the decode or value options, and will be fed to the resulting object’s decode method or value property, respectively.

class aiocoap.ContentFormat

Bases: aiocoap.util.ExtensibleIntEnum

Entry in the CoAP Content-Formats registry of the IANA Constrained RESTful Environments (Core) Parameters group

Known entries have .media_type and .encoding attributes:

>>> ContentFormat(0).media_type
'text/plain; charset=utf-8'
>>> int(ContentFormat.by_media_type('text/plain;charset=utf-8'))
0
>>> ContentFormat(60)
<ContentFormat 60, media_type='application/cbor', encoding='identity'>
>>> ContentFormat(11060).encoding
'deflate'

Unknown entries do not have these properties:

>>> ContentFormat(12345).is_known()
False
>>> ContentFormat(12345).media_type                    # doctest: +ELLIPSIS
Traceback (most recent call last):
    ...
AttributeError: ...

Only a few formats are available as attributes for easy access. Their selection and naming are arbitrary and biased. The remaining known types are available through the by_media_type() class method. >>> ContentFormat.TEXT <ContentFormat 0, media_type=’text/plain; charset=utf-8’, encoding=’identity’>

A convenient property of ContentFormat is that any known content format is true in a boolean context, and thus when used in alternation with None, can be assigned defaults easily:

>>> requested_by_client = ContentFormat.TEXT
>>> int(requested_by_client) # Usually, this would always pick the default
0
>>> used = requested_by_client or ContentFormat.LINKFORMAT
>>> assert used == ContentFormat.TEXT
classmethod by_media_type(media_type: str, encoding: str = 'identity') → aiocoap.numbers.contentformat.ContentFormat

Produce known entry for a known media type (and encoding, though ‘identity’ is default due to its prevalence), or raise KeyError.

is_known()
TEXT = <ContentFormat 0, media_type='text/plain; charset=utf-8', encoding='identity'>
LINKFORMAT = <ContentFormat 40, media_type='application/link-format', encoding='identity'>
OCTETSTREAM = <ContentFormat 42, media_type='application/octet-stream', encoding='identity'>
JSON = <ContentFormat 50, media_type='application/json', encoding='identity'>
CBOR = <ContentFormat 60, media_type='application/cbor', encoding='identity'>
SENML = <ContentFormat 112, media_type='application/senml+cbor', encoding='identity'>
class aiocoap.Message(*, mtype=None, mid=None, code=None, payload=b'', token=b'', uri=None, **kwargs)

Bases: object

CoAP Message with some handling metadata

This object’s attributes provide access to the fields in a CoAP message and can be directly manipulated.

  • Some attributes are additional data that do not round-trip through serialization and deserialization. They are marked as “non-roundtrippable”.
  • Some attributes that need to be filled for submission of the message can be left empty by most applications, and will be taken care of by the library. Those are marked as “managed”.

The attributes are:

  • payload: The payload (body) of the message as bytes.

  • mtype: Message type (CON, ACK etc, see numbers.types). Managed unless set by the application.

  • code: The code (either request or response code), see numbers.codes.

  • opt: A container for the options, see options.Options.

  • mid: The message ID. Managed by the Context.

  • token: The message’s token as bytes. Managed by the Context.

  • remote: The socket address of the other side, managed by the protocol.Request by resolving the .opt.uri_host or unresolved_remote, or the Responder by echoing the incoming request’s. Follows the interfaces.EndpointAddress interface. Non-roundtrippable.

    While a message has not been transmitted, the property is managed by the Message itself using the set_request_uri() or the constructor uri argument.

  • request: The request to which an incoming response message belongs; only available at the client. Managed by the interfaces.RequestProvider (typically a Context).

These properties are still available but deprecated:

  • requested_*: Managed by the protocol.Request a response results from, and filled with the request’s URL data. Non-roundtrippable.

  • unresolved_remote: host[:port] (strictly speaking; hostinfo as in a URI) formatted string. If this attribute is set, it overrides .RequestManageropt.uri_host (and -_port) when it comes to filling the remote in an outgoing request.

    Use this when you want to send a request with a host name that would not normally resolve to the destination address. (Typically, this is used for proxying.)

Options can be given as further keyword arguments at message construction time. This feature is experimental, as future message parameters could collide with options.

Requester                                  Responder

+-------------+                          +-------------+
| request msg |  ---- send request --->  | request msg |
+-------------+                          +-------------+
                                               |
                                          processed into
                                               |
                                               v
+-------------+                          +-------------+
| response m. |  <--- send response ---  | response m. |
+-------------+                          +-------------+

The above shows the four message instances involved in communication between an aiocoap client and server process. Boxes represent instances of Message, and the messages on the same line represent a single CoAP as passed around on the network. Still, they differ in some aspects:

  • The requested URI will look different between requester and responder if the requester uses a host name and does not send it in the message.
  • If the request was sent via multicast, the response’s requested URI differs from the request URI because it has the responder’s address filled in. That address is not known at the responder’s side yet, as it is typically filled out by the network stack.
  • It is yet unclear whether the response’s URI should contain an IP literal or a host name in the unicast case if the Uri-Host option was not sent.
  • Properties like Message ID and token will differ if a proxy was involved.
  • Some options or even the payload may differ if a proxy was involved.
copy(**kwargs)

Create a copy of the Message. kwargs are treated like the named arguments in the constructor, and update the copy.

classmethod decode(rawdata, remote=None)

Create Message object from binary representation of message.

encode()

Create binary representation of message from Message object.

get_cache_key(ignore_options=())

Generate a hashable and comparable object (currently a tuple) from the message’s code and all option values that are part of the cache key and not in the optional list of ignore_options (which is the list of option numbers that are not technically NoCacheKey but handled by the application using this method).

>>> from aiocoap.numbers import GET
>>> m1 = Message(code=GET)
>>> m2 = Message(code=GET)
>>> m1.opt.uri_path = ('s', '1')
>>> m2.opt.uri_path = ('s', '1')
>>> m1.opt.size1 = 10 # the only no-cache-key option in the base spec
>>> m2.opt.size1 = 20
>>> m1.get_cache_key() == m2.get_cache_key()
True
>>> m2.opt.etag = b'000'
>>> m1.get_cache_key() == m2.get_cache_key()
False
>>> from aiocoap.numbers.optionnumbers import OptionNumber
>>> ignore = [OptionNumber.ETAG]
>>> m1.get_cache_key(ignore) == m2.get_cache_key(ignore)
True
get_request_uri(*, local_is_server=False)

The absolute URI this message belongs to.

For requests, this is composed from the options (falling back to the remote). For responses, this is largely taken from the original request message (so far, that could have been trackecd by the requesting application as well), but – in case of a multicast request – with the host replaced by the responder’s endpoint details.

This implements Section 6.5 of RFC7252.

By default, these values are only valid on the client. To determine a message’s request URI on the server, set the local_is_server argument to True. Note that determining the request URI on the server is brittle when behind a reverse proxy, may not be possible on all platforms, and can only be applied to a request message in a renderer (for the response message created by the renderer will only be populated when it gets transmitted; simple manual copying of the request’s remote to the response will not magically make this work, for in the very case where the request and response’s URIs differ, that would not catch the difference and still report the multicast address, while the actual sending address will only be populated by the operating system later).

set_request_uri(uri, *, set_uri_host=True)

Parse a given URI into the uri_* fields of the options.

The remote does not get set automatically; instead, the remote data is stored in the uri_host and uri_port options. That is because name resolution is coupled with network specifics the protocol will know better by the time the message is sent. Whatever sends the message, be it the protocol itself, a proxy wrapper or an alternative transport, will know how to handle the information correctly.

When set_uri_host=False is passed, the host/port is stored in the unresolved_remote message property instead of the uri_host option; as a result, the unresolved host name is not sent on the wire, which breaks virtual hosts but makes message sizes smaller.

This implements Section 6.4 of RFC7252.

unresolved_remote
requested_scheme
requested_proxy_uri
requested_hostinfo
requested_path
requested_query
class aiocoap.Context(loop=None, serversite=None, loggername='coap', client_credentials=None, server_credentials=None)

Bases: aiocoap.interfaces.RequestProvider

Applications’ entry point to the network

A Context coordinates one or more network transports implementations and dispatches data between them and the application.

The application can start requests using the message dispatch methods, and set a resources.Site that will answer requests directed to the application as a server.

On the library-internals side, it is the prime implementation of the interfaces.RequestProvider interface, creates Request and Response classes on demand, and decides which transport implementations to start and which are to handle which messages.

Context creation and destruction

The following functions are provided for creating and stopping a context:

Note

A typical application should only ever create one context, even (or especially when) it acts both as a server and as a client (in which case a server context should be created).

A context that is not used any more must be shut down using shutdown(), but typical applications will not need to because they use the context for the full process lifetime.

classmethod create_client_context(*, loggername='coap', loop=None, transports: Optional[List[str]] = None)

Create a context bound to all addresses on a random listening port.

This is the easiest way to get a context suitable for sending client requests.

classmethod create_server_context(site, bind=None, *, loggername='coap-server', loop=None, _ssl_context=None, multicast=[], server_credentials=None, transports: Optional[List[str]] = None)

Create a context, bound to all addresses on the CoAP port (unless otherwise specified in the bind argument).

This is the easiest way to get a context suitable both for sending client and accepting server requests.

The bind argument, if given, needs to be a 2-tuple of IP address string and port number, where the port number can be None to use the default port.

If multicast is given, it needs to be a list of (multicast address, interface name) tuples, which will all be joined. (The IPv4 style of selecting the interface by a local address is not supported; users may want to use the netifaces package to arrive at an interface name for an address).

As a shortcut, the list may also contain interface names alone. Those will be joined for the ‘all CoAP nodes’ groups of IPv4 and IPv6 (with scopes 2 and 5) as well as the respective ‘all nodes’ groups in IPv6.

Under some circumstances you may already need a context to pass into the site for creation; this is typically the case for servers that trigger requests on their own. For those cases, it is usually easiest to pass None in as a site, and set the fully constructed site later by assigning to the serversite attribute.

shutdown()

Take down any listening sockets and stop all related timers.

After this coroutine terminates, and once all external references to the object are dropped, it should be garbage-collectable.

This method takes up to aiocoap.numbers.constants.SHUTDOWN_TIMEOUT seconds, allowing transports to perform any cleanup implemented in them (such as orderly connection shutdown and cancelling observations, where the latter is currently not implemented).

Dispatching messages

CoAP requests can be sent using the following functions:

request(request_message, handle_blockwise=True)

Create and act on a a Request object that will be handled according to the provider’s implementation.

Note that the request is not necessarily sent on the wire immediately; it may (but, depend on the transport does not necessarily) rely on the response to be waited for.

If more control is needed, you can create a Request yourself and pass the context to it.

Other methods and properties

The remaining methods and properties are to be considered unstable even when the project reaches a stable version number; please file a feature request for stabilization if you want to reliably access any of them.

(Sorry for the duplicates, still looking for a way to make autodoc list everything not already mentioned).

request(request_message, handle_blockwise=True)

Create and act on a a Request object that will be handled according to the provider’s implementation.

Note that the request is not necessarily sent on the wire immediately; it may (but, depend on the transport does not necessarily) rely on the response to be waited for.

render_to_pipe(pipe)

Fill a pipe by running the site’s render_to_pipe interface and handling errors.

classmethod create_client_context(*, loggername='coap', loop=None, transports: Optional[List[str]] = None)

Create a context bound to all addresses on a random listening port.

This is the easiest way to get a context suitable for sending client requests.

classmethod create_server_context(site, bind=None, *, loggername='coap-server', loop=None, _ssl_context=None, multicast=[], server_credentials=None, transports: Optional[List[str]] = None)

Create a context, bound to all addresses on the CoAP port (unless otherwise specified in the bind argument).

This is the easiest way to get a context suitable both for sending client and accepting server requests.

The bind argument, if given, needs to be a 2-tuple of IP address string and port number, where the port number can be None to use the default port.

If multicast is given, it needs to be a list of (multicast address, interface name) tuples, which will all be joined. (The IPv4 style of selecting the interface by a local address is not supported; users may want to use the netifaces package to arrive at an interface name for an address).

As a shortcut, the list may also contain interface names alone. Those will be joined for the ‘all CoAP nodes’ groups of IPv4 and IPv6 (with scopes 2 and 5) as well as the respective ‘all nodes’ groups in IPv6.

Under some circumstances you may already need a context to pass into the site for creation; this is typically the case for servers that trigger requests on their own. For those cases, it is usually easiest to pass None in as a site, and set the fully constructed site later by assigning to the serversite attribute.

find_remote_and_interface(message)
shutdown()

Take down any listening sockets and stop all related timers.

After this coroutine terminates, and once all external references to the object are dropped, it should be garbage-collectable.

This method takes up to aiocoap.numbers.constants.SHUTDOWN_TIMEOUT seconds, allowing transports to perform any cleanup implemented in them (such as orderly connection shutdown and cancelling observations, where the latter is currently not implemented).