Skip to main content

Using CoAP with Memfault

The Constrained Application Protocol (CoAP) is a UDP-based application-layer protocol, and is a common alternative to HTTP(S) over TCP on devices with limited compute or connectivity. When designing such devices, CoAP is the recommended alternative to HTTPS. Because Memfault only has HTTPS - not CoAP - endpoints, the remainder of this document outlines two options for relaying data to Memfault via CoAP.

  1. Nordic nRF Cloud CoAP-to-HTTPS relay for Nordic Cellular products
  2. Self-hosting a CoAP-to-HTTPS proxy

1. Nordic nRF9x CoAP-to-HTTPS relay

When designing products with Nordic cellular chips, customers have access to nRF Cloud's CoAP Server's relay functionality. Among other features (e.g. location services), this CoAP server offers CoAP-to-HTTPS functionality integrated with Memfault's HTTPS-based API. This relay is available to nRF9160 and 91x1 customers at no extra charge.

Secure authentication and communication over CoAP to that relay are fully implemented and abstracted in NCS, and can be enabled via Kconfig. More detail on that is covered in the Nordic Cellular Quickstart guide.

The relay service is not currently available to any other chipsets outside nRF9160 and 91x1.

Additional information about the nRF Cloud CoAP API can be found here.

2. CoAP-to-HTTPS Proxy

A CoAP-to-HTTPS proxy can be used to forward data from a device to Memfault. The proxy listens for CoAP packets and forwards them to Memfault's servers using HTTP. This approach allows devices to communicate with Memfault without implementing an HTTPS client.

A simple example CoAP-HTTPS proxy in Python:

coap-proxy.py
# Implement a COAP-to-HTTPS proxy to forward requests to
# https://chunks.memfault.com/api/v0/chunks/

import asyncio
import logging
import os

# Install dependencies:
# pip install aiocoap requests
import aiocoap
import aiocoap.resource as resource
import requests

# Set up logging
logging.basicConfig(
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
level=logging.INFO,
)
LOG = logging.getLogger("coap-proxy")


class ChunkEndpoint(resource.Resource):
"""
Forwards POST requests to Memfault's HTTPS chunks endpoint, and returns the
response, with a hard-coded serial number and Project Key from an
environment variable.
"""
def __init__(self):
super().__init__()

async def render_post(self, request):
LOG.info("POST payload: %s" % repr(request.payload))

coap_payload = request.payload
coap_url = "https://chunks.memfault.com/api/v0/chunks/TEST_SERIAL"

# need to set the Memfault-Project-Key: <YOUR_PROJECT_KEY> header
# to authenticate the request
headers = {
"Memfault-Project-Key": os.getenv("MEMFAULT_PROJECT_KEY"),
"Content-Type": "application/octet-stream",
}

# Forward the COAP request to the HTTPS endpoint
response = requests.post(coap_url, data=coap_payload, headers=headers)

LOG.info("HTTPS response: %s" % response.status_code)
LOG.info("HTTPS response content: %s" % response.content)

# Create a COAP response with the HTTPS response content
return aiocoap.Message(code=aiocoap.CONTENT, payload=response.content)


async def main():
# Resource tree creation
root = resource.Site()

root.add_resource(
[".well-known", "core"], resource.WKCResource(root.get_resources_as_linkheader)
)
root.add_resource(["chunks"], ChunkEndpoint())

await aiocoap.Context.create_server_context(root)

LOG.info("COAP server started")

# Run forever
await asyncio.get_running_loop().create_future()


if __name__ == "__main__":
asyncio.run(main())

When running it, set the MEMFAULT_PROJECT_KEY environment variable to your Project Key.

After starting the server, a request can be issued with the libcoap coap-client tool:

❯ examples/coap-client -m post -f ~/Downloads/chunk_v2_single_chunk_msg-f48b401be2528a137495ab4f8ec2202f.bin 'coap://[::]/chunks'
Accepted

The server will proxy the request and return a response:

❯ MEMFAULT_PROJECT_KEY="<Project Key>" python coap-proxy.py
2024-06-24 16:15:54,104 - coap-proxy - INFO - COAP server started
2024-06-24 16:15:55,391 - coap-proxy - INFO - POST payload: b'\x08\x02\xa7\x02\x01\x03\x01\x07jTESTSERIAL\nmtest-software\tj1.0.0-test\x06mtest-hardware\x04\xa1\x01\xa1rchunk_test_success\x011\xe4'
2024-06-24 16:15:55,535 - coap-proxy - INFO - HTTPS response: 202
2024-06-24 16:15:55,535 - coap-proxy - INFO - HTTPS response content: b'Accepted'