%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D'}}}%%
sequenceDiagram
participant C as Client
participant S as Server
C->>S: GET /firmware/update.bin
Note right of C: Block2: NUM=0, SIZE=1024
S->>C: 2.05 Content
Note left of S: Block2: NUM=0, M=1<br/>Payload: [1024 bytes]
C->>S: GET /firmware/update.bin
Note right of C: Block2: NUM=1, SIZE=1024
S->>C: 2.05 Content
Note left of S: Block2: NUM=1, M=1<br/>Payload: [1024 bytes]
Note over C,S: ... continues for 256KB / 1KB = 256 blocks ...
C->>S: GET /firmware/update.bin
Note right of C: Block2: NUM=255, SIZE=1024
S->>C: 2.05 Content
Note left of S: Block2: NUM=255, M=0<br/>Payload: [final bytes]<br/>(M=0 = last block)
1216 CoAP Advanced Features: Block Transfer, Discovery, and TCP
1216.1 Learning Objectives
By the end of this chapter, you will be able to:
- Implement Block-wise Transfer: Handle large payloads (firmware updates) over CoAPโs UDP transport
- Configure Resource Discovery: Set up
.well-known/corewith CoRE Link Format - Choose CoAP Transport: Decide between UDP, TCP, and WebSockets based on requirements
- Deploy DTLS Security: Secure CoAP communications with appropriate cipher suites
1216.2 Prerequisites
Before diving into this chapter, you should be familiar with:
- CoAP Introduction - CoAP basics and design goals
- CoAP Message Format - Header structure and options
- CoAP Observe Extension - Server push notifications
1216.3 Block-wise Transfer (RFC 7959)
Core Concept: CoAP messages are limited by UDP MTU (1280-1500 bytes), but firmware updates or images require 100KB+ payloads. Block-wise transfer splits large payloads into sequential blocks with automatic reassembly.
Why It Matters: Without block transfer, CoAP couldnโt handle firmware OTA updates, large configuration files, or image uploads - essential for production IoT deployments.
Key Takeaway: Use Block2 for large response payloads (downloads), Block1 for large request payloads (uploads). Each block includes block number, more-flag, and size.
1216.3.1 Block2: Large Response Payloads
Used when server sends large data to client (e.g., firmware download):
Block2 option format: - NUM: Block number (0-based sequence) - M: More flag (1 = more blocks follow, 0 = last block) - SIZE: Block size in bytes (16, 32, 64, 128, 256, 512, 1024)
1216.3.2 Block1: Large Request Payloads
Used when client sends large data to server (e.g., uploading logs):
Client -> Server: PUT /logs/daily
Block1: NUM=0, M=1, SIZE=512
Payload: [first 512 bytes]
Server -> Client: 2.31 Continue
Block1: NUM=0, M=1, SIZE=512
Client -> Server: PUT /logs/daily
Block1: NUM=1, M=1, SIZE=512
Payload: [next 512 bytes]
... until final block with M=0 ...
Server -> Client: 2.04 Changed
1216.3.3 Implementation with Reliability
async def download_firmware(uri, output_file):
block_num = 0
block_size = 1024
consecutive_failures = 0
with open(output_file, 'wb') as f:
while True:
# Adaptive timeout with exponential backoff
timeout = min(2.0 * (1.5 ** consecutive_failures), 30.0)
try:
request = Message(
code=GET,
uri=uri,
msg_type=CON, # Reliable for each block
block2=(block_num, False, block_size)
)
response = await protocol.request(request, timeout=timeout).response
# Write block to file
f.write(response.payload)
consecutive_failures = 0
# Check if more blocks available
if response.opt.block2.more:
block_num += 1
else:
break # Last block received
except TimeoutError:
consecutive_failures += 1
if consecutive_failures > 10:
raise TransferFailed(f"Failed at block {block_num}")
print(f"Downloaded {block_num + 1} blocks")1216.3.4 Performance Analysis
Scenario: 256 KB firmware update over LoRaWAN (10% packet loss)
| Approach | Blocks | Retransmissions | Time | Success Rate |
|---|---|---|---|---|
| Single 256KB payload | 1 | Many | 146s | ~65% |
| 1KB blocks (NON) | 256 | 0 | 51s | ~11% |
| 1KB blocks + CON | 256 | Avg 1.11/block | 57s | ~99.99% |
| 512 byte blocks + CON | 512 | Avg 1.05/block | 54s | ~99.999% |
Key insight: Smaller blocks = higher success rate on lossy links, but more overhead.
1216.4 Resource Discovery (RFC 6690)
Core Concept: Every CoAP server exposes a standardized /.well-known/core endpoint that returns a machine-readable list of all available resources with their URIs, types, interfaces, and capabilities in Link Format (RFC 6690).
Why It Matters: Resource discovery enables true plug-and-play IoT - new devices can be added to a network and automatically discovered by clients without manual configuration.
Key Takeaway: Always implement /.well-known/core with semantic attributes (rt= for resource type, if= for interface, obs for observability).
1216.4.1 Discovery Request-Response
Client Request:
GET coap://sensor.local/.well-known/core
Server Response (Link Format, Content-Format: 40):
</sensors/temp>;rt="temperature";if="sensor";obs,
</sensors/humidity>;rt="humidity";if="sensor";obs,
</sensors/pressure>;rt="pressure";if="sensor",
</actuators/led>;rt="light";if="actuator",
</config/interval>;rt="config";if="parameter"
1216.4.2 Link Format Attributes
| Attribute | Meaning | Example |
|---|---|---|
| rt | Resource Type | rt="temperature" |
| if | Interface | if="sensor" |
| ct | Content Format | ct=50 (JSON) |
| sz | Max Size | sz=256 |
| obs | Observable | obs (flag) |
| title | Human Name | title="Room Temp" |
1216.4.3 Filtered Discovery
Request only specific resource types:
# Find all temperature sensors
GET coap://sensor.local/.well-known/core?rt=temperature
Response:
</sensors/temp>;rt="temperature";if="sensor";obs,
</sensors/temp_outdoor>;rt="temperature";if="sensor";obs
# Find all observable resources
GET coap://sensor.local/.well-known/core?obs
1216.4.4 Multicast Discovery
Discover all CoAP devices on network simultaneously:
GET coap://[FF02::FD]/.well-known/core
# All CoAP devices respond with their resource list
Device 1: </temp>;rt="temperature"
Device 2: </humidity>;rt="humidity"
Device 3: </pressure>;rt="pressure"
1216.5 CoAP over TCP (RFC 8323)
1216.5.1 Why CoAP-over-TCP?
Problem: UDP works great for constrained devices, but some networks: - Block UDP entirely (corporate firewalls) - Have asymmetric NAT breaking UDP return paths - Require guaranteed ordering (financial transactions)
Solution: RFC 8323 defines CoAP over reliable transports (TCP, TLS, WebSockets).
1216.5.2 Protocol Differences
| Feature | CoAP/UDP | CoAP/TCP |
|---|---|---|
| Transport | Unreliable UDP | Reliable TCP |
| Message Types | CON, NON, ACK, RST | Signaling only |
| Reliability | Application (CON/ACK) | Transport (TCP) |
| Message ID | Required | Optional |
| Connection | None | TCP 3-way handshake |
| Default Port | 5683 (coap://) | 5683 (coap+tcp://) |
| Secure Port | 5684 (coaps://) | 443 (coaps+tcp://) |
1216.5.3 Header Format Changes
CoAP/UDP header (4 bytes):
|Ver| T | TKL | Code | Message ID |
CoAP/TCP header (2-4 bytes):
| Len | TKL | Code | Token |
Key changes: - No Message ID (TCP sequence numbers handle ordering) - No Type field (TCP reliability eliminates CON/NON/ACK) - Length field (for framing over stream)
1216.5.4 When to Use
Use CoAP/TCP when: - Corporate/enterprise networks block UDP - Web dashboard integration (WebSockets) - Guaranteed ordering requirements - Long-lived bidirectional streams
Avoid CoAP/TCP when: - Battery-powered sensors (UDP more efficient) - Multicast scenarios (TCP is unicast only) - Intermittent communication (connection overhead wasteful)
1216.6 DTLS Security
CoAP uses DTLS (Datagram TLS) for security over UDP:
1216.6.1 Security Modes
| Mode | Description | Use Case |
|---|---|---|
| NoSec | No security | Development only |
| PreSharedKey | Symmetric keys pre-installed | Factory provisioning |
| RawPublicKey | Asymmetric without certificates | Lightweight devices |
| Certificate | Full X.509 certificates | Enterprise deployments |
1216.6.2 DTLS Handshake
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#ecf0f1'}}}%%
sequenceDiagram
participant Client as CoAP Client
participant Server as CoAP Server
Client->>Server: ClientHello
Server->>Client: HelloVerifyRequest (cookie)
Client->>Server: ClientHello (with cookie)
Server->>Client: ServerHello, Certificate
Client->>Server: Certificate, ClientKeyExchange
Server->>Client: ChangeCipherSpec, Finished
Client->>Server: ChangeCipherSpec, Finished
Note over Client,Server: Secure DTLS session established
Client->>Server: Encrypted CoAP GET /sensor
Server->>Client: Encrypted 2.05 Content
1216.7 Common Pitfalls
The Mistake: Using default CoAP timeout values for block-wise transfers, causing transfer failures at 60-80% completion on lossy links.
Why It Happens: CoAPโs 2-second ACK timeout works for single messages but fails for multi-block transfers. Any single timeout can cause restart.
The Fix: Implement adaptive timeouts and resumable transfers:
def download_with_resume(uri, resume_from=0):
block_num = resume_from
consecutive_failures = 0
base_timeout = 2.0
while True:
timeout = min(base_timeout * (1.5 ** consecutive_failures), 30.0)
try:
response = coap_get(uri, block2=(block_num, 0, 1024), timeout=timeout)
save_progress(block_num, response.payload)
consecutive_failures = 0
if response.block2.more:
block_num += 1
else:
return assemble_firmware()
except TimeoutError:
consecutive_failures += 1
if consecutive_failures > 10:
save_resume_point(block_num)
raise TransferSuspended(block_num)The Mistake: Deploying CoAP devices behind NAT gateways without considering that UDP NAT mappings expire quickly (30-120 seconds).
The Fix: - Test UDP connectivity before design - Implement NAT keepalive (send messages every 25 seconds) - Consider CoAP over TCP for NAT-hostile networks - Use DTLS session resumption for faster reconnects
1216.8 Summary
CoAPโs advanced features enable production IoT deployments:
- Block-wise transfer: Split large payloads into reliable blocks
- Resource discovery: Standardized
.well-known/corewith Link Format - CoAP/TCP: Firewall-friendly alternative when UDP is blocked
- DTLS security: Encryption and authentication for constrained devices
Key decisions: - Use smaller blocks (256-512 bytes) on lossy networks - Always implement resource discovery with semantic attributes - Choose UDP for battery efficiency, TCP for NAT/firewall traversal - Use PSK for constrained devices, certificates for enterprise
1216.9 Whatโs Next
Now that you understand advanced features:
- API Design: CoAP API Design - RESTful patterns and best practices
- Protocol Selection: CoAP Decision Framework - When to use CoAP vs MQTT vs HTTP
- See All CoAP Topics: CoAP Fundamentals and Architecture - Complete chapter index