CoAP defines four message types: Confirmable (CON) requires acknowledgment for reliable delivery of critical commands, Non-Confirmable (NON) provides fire-and-forget efficiency for frequent sensor readings, Acknowledgment (ACK) confirms CON receipt and can piggyback the response payload, and Reset (RST) indicates the receiver cannot process the message. The CON vs NON choice directly trades reliability for energy – CON costs up to 16x the energy of NON (due to ACK wait and RX radio time) but achieves 99.99% delivery.
43.1 Learning Objectives
By the end of this chapter, you will be able to:
Distinguish the four CoAP message types (CON, NON, ACK, RST) and their roles in the protocol
Select the appropriate message type based on reliability requirements and battery constraints
Explain piggyback vs separate response patterns and when each is used
Calculate the energy trade-off between CON and NON messages for battery-powered devices
Key Concepts
CoAP: Constrained Application Protocol — REST-style request/response protocol using UDP instead of TCP
Confirmable Message (CON): Requires ACK from recipient — provides reliable delivery over UDP at the cost of one roundtrip
Observe Option: CoAP extension enabling publish/subscribe: client registers to receive notifications on resource changes
Block-wise Transfer: Fragmentation mechanism for transferring payloads larger than a single CoAP datagram
Token: Client-generated value matching responses to requests — enables concurrent request/response pairing
DTLS: Datagram TLS — CoAP’s security layer providing encryption and authentication over UDP
43.2 For Beginners: CoAP Message Types
CoAP uses four message types: Confirmable (requires acknowledgment), Non-confirmable (fire-and-forget), Acknowledgment (confirmation receipt), and Reset (error signal). Think of it like different ways to send a message – sometimes you need a read receipt, sometimes you just want to shout the news without waiting for a reply.
Sensor Squad: Four Ways to Send a Message
“I have four different ways to send my readings?” asked Sammy the Sensor, confused.
“Think of it like four types of mail!” said Max the Microcontroller. “Confirmable (CON) is like certified mail – you send it and wait for a signed receipt. If you don’t get one, you send it again. Perfect for important alerts like ‘the freezer door is open!’”
Lila the LED continued: “Non-confirmable (NON) is like dropping a flyer in someone’s mailbox – you don’t wait to see if they read it. Great for routine updates like ‘living room light is still on.’ If one update gets lost, another is coming in 10 seconds anyway.”
“Then there’s the Acknowledgment (ACK),” said Bella the Battery. “That’s the signed receipt itself – you’re saying ‘yep, I got your message!’ And Reset (RST) is like returning a letter stamped ‘wrong address’ – it means ‘I don’t understand what you’re asking for.’ Four simple types cover every situation, and they keep the protocol tiny!”
43.3 CoAP Message Types
Four message types provide flexibility for different scenarios:
43.3.1 Confirmable (CON)
Reliable transmission - requires acknowledgment:
Figure 43.1: CoAP Confirmable Message Exchange with Acknowledgment
Choosing between Confirmable (CON) and Non-Confirmable (NON) messages dramatically impacts battery life:
CON (Confirmable):
Waits for ACK response (50-200ms typical)
Retransmits if no ACK (exponential backoff)
Radio stays on longer → drains battery
Use for: Critical commands, infrequent updates
NON (Non-Confirmable):
Fire-and-forget, no waiting
Radio on for <10ms
5-10x better battery life than CON
Use for: Frequent sensor readings where occasional loss is acceptable
Example: Temperature sensor sending readings every 60 seconds - battery lasts 2 years with NON vs 3 months with CON. For battery-powered devices, default to NON and use CON only when absolutely necessary.
Figure 43.3: Alternative view: CoAP message type comparison showing the flow and resource usage differences between Confirmable (CON) and Non-Confirmable (NON) messages. CON provides reliability through retransmission but consumes 5-10x more battery, while NON offers fire-and-forget efficiency suitable for frequent sensor readings.
43.3.3 Worked Example: CON vs NON Energy Budget for Cold Chain Monitoring
Scenario: A pharmaceutical warehouse uses 200 CoAP sensors monitoring freezer temperatures. Each sensor sends a 20-byte reading every 30 seconds. Sensors use 802.15.4 radios (250 Kbps) with 8 mA TX, 5 mA RX current at 3.0V. Battery: 1,000 mAh CR123A.
For NON messages (no ACK wait): \[
E_{\text{NON}} = I_{\text{TX}} \cdot t_{\text{TX}} + I_{\text{startup}} \cdot t_{\text{startup}}
\]
For CON messages (with ACK wait): \[
E_{\text{CON}} = E_{\text{NON}} + I_{\text{RX}} \cdot t_{\text{ACK\_wait}} + I_{\text{RX}} \cdot t_{\text{ACK\_RX}}
\]
Where \(I_{\text{TX}} = 8\text{ mA}\), \(I_{\text{RX}} = 5\text{ mA}\) at \(V = 3.0\text{ V}\) for 802.15.4.
The energy ratio: \[
\frac{E_{\text{CON}}}{E_{\text{NON}}} = \frac{0.272}{0.017} \approx 16\times
\]
This 16× multiplier directly translates to battery life reduction when switching from NON to CON for frequent sensor readings.
CON message energy per transmission:
TX same as NON: 0.017 mAs
Wait for ACK: radio in RX mode ~50 ms at 5 mA = 0.25 mAs (typical RTT on local network)
ACK reception: 4-byte header + 8 UDP + 20 IPv6 = 32 bytes at 5 mA = 0.005 mAs
Total per CON: 0.272 mAs (16x more than NON)
Battery lifetime comparison:
Metric
NON
CON
Energy per message
0.017 mAs
0.272 mAs
Messages per day
2,880
2,880
Daily consumption
49 mAs = 0.0136 mAh
784 mAs = 0.218 mAh
Battery lifetime
1,000 / 0.0136 = 73,529 days
1,000 / 0.218 = 4,587 days
Practical lifetime (with sleep current)
~8 years
~5 years
But what about reliability? With 5% packet loss on 802.15.4:
NON: 5% of readings lost = 144 per day (but next reading arrives in 30 seconds)
CON: 0.0025% loss after retransmission (5% x 5% = 0.25% after one retry)
Decision: Use NON for routine 30-second temperature readings (any loss is replaced in 30 seconds). Use CON only for threshold alerts (“Temperature exceeded -18C”) which happen rarely (~2 per day). This hybrid approach achieves ~8-year battery life while guaranteeing critical alerts are delivered.
43.4 Interactive: CoAP Message Energy Calculator
Explore how message type, transmission frequency, and network parameters affect battery life:
Show code
viewof payloadSize = Inputs.range([1,1024], {value:20,step:1,label:"Payload size (bytes)"})viewof transmitInterval = Inputs.range([1,300], {value:30,step:1,label:"Transmit interval (seconds)"})viewof messageType = Inputs.select(["NON","CON","Hybrid"], {value:"NON",label:"Message type"})viewof batteryCapacity = Inputs.range([100,5000], {value:1000,step:100,label:"Battery capacity (mAh)"})viewof ackWaitTime = Inputs.range([10,200], {value:50,step:10,label:"ACK wait time (ms)"})// Radio parameters (802.15.4 typical)radioParams = ({txCurrent:8,// mArxCurrent:5,// mAstartupTime:0.5,// msdataRate:250000,// bpsvoltage:3.0// V})// Calculate packet size (CoAP + UDP + IPv6 headers)totalPacketSize = payloadSize +4+8+20// Calculate TX time in millisecondstxTime = (totalPacketSize *8) / radioParams.dataRate*1000// Energy calculationsenergyNON = ( radioParams.txCurrent* txTime + radioParams.txCurrent* radioParams.startupTime) /1000// Convert to mAsenergyCON = ( energyNON + radioParams.rxCurrent* ackWaitTime /1000+ radioParams.rxCurrent*0.005// ACK reception)// Messages per daymessagesPerDay = (24*3600) / transmitInterval// Daily energy consumptiondailyEnergyNON = (energyNON * messagesPerDay) /3600// Convert mAs to mAhdailyEnergyCON = (energyCON * messagesPerDay) /3600// Hybrid: 95% NON, 5% CON (typical for sensor with occasional alerts)dailyEnergyHybrid = (0.95* dailyEnergyNON) + (0.05* dailyEnergyCON)// Battery lifetime in dayslifetimeNON = batteryCapacity / dailyEnergyNONlifetimeCON = batteryCapacity / dailyEnergyCONlifetimeHybrid = batteryCapacity / dailyEnergyHybrid// Determine which value to show based on message typeselectedDailyEnergy = messageType ==="NON"? dailyEnergyNON : messageType ==="CON"? dailyEnergyCON : dailyEnergyHybridselectedLifetime = messageType ==="NON"? lifetimeNON : messageType ==="CON"? lifetimeCON : lifetimeHybridhtml`<div style="font-family: Arial, sans-serif; max-width: 800px; margin: 20px 0;"> <div style="background: linear-gradient(135deg, #2C3E50 0%, #3498DB 100%); color: white; padding: 20px; border-radius: 8px; margin-bottom: 20px;"> <h3 style="margin: 0 0 10px 0; color: white;">CoAP Message Energy Analysis</h3> <div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px; margin-top: 15px;"> <div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 6px;"> <div style="font-size: 12px; opacity: 0.9; margin-bottom: 5px;">Total Packet Size</div> <div style="font-size: 24px; font-weight: bold;">${totalPacketSize} bytes</div> <div style="font-size: 11px; opacity: 0.8; margin-top: 5px;">${payloadSize} payload + 32 headers </div> </div> <div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 6px;"> <div style="font-size: 12px; opacity: 0.9; margin-bottom: 5px;">TX Time</div> <div style="font-size: 24px; font-weight: bold;">${txTime.toFixed(2)} ms</div> <div style="font-size: 11px; opacity: 0.8; margin-top: 5px;"> at 250 Kbps data rate </div> </div> <div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 6px;"> <div style="font-size: 12px; opacity: 0.9; margin-bottom: 5px;">Messages/Day</div> <div style="font-size: 24px; font-weight: bold;">${messagesPerDay.toLocaleString()}</div> <div style="font-size: 11px; opacity: 0.8; margin-top: 5px;"> every ${transmitInterval}s </div> </div> <div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 6px;"> <div style="font-size: 12px; opacity: 0.9; margin-bottom: 5px;">Daily Energy (${messageType})</div> <div style="font-size: 24px; font-weight: bold;">${selectedDailyEnergy.toFixed(3)} mAh</div> <div style="font-size: 11px; opacity: 0.8; margin-top: 5px;">${(selectedDailyEnergy *1000/ batteryCapacity).toFixed(2)}% of battery </div> </div> </div> </div> <div style="background: #f8f9fa; padding: 20px; border-radius: 8px; border-left: 4px solid #16A085;"> <h4 style="margin: 0 0 15px 0; color: #2C3E50;">Battery Lifetime Estimate</h4> <div style="font-size: 36px; font-weight: bold; color: #16A085; margin-bottom: 10px;">${selectedLifetime >365? (selectedLifetime /365).toFixed(1) +' years':Math.floor(selectedLifetime) +' days'} </div> <div style="font-size: 14px; color: #7F8C8D; margin-bottom: 15px;"> with ${batteryCapacity} mAh battery capacity </div> <div style="background: white; padding: 15px; border-radius: 6px; margin-top: 15px;"> <div style="font-size: 13px; font-weight: 600; color: #2C3E50; margin-bottom: 10px;">Energy Comparison</div> <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; text-align: center;"> <div> <div style="font-size: 11px; color: #7F8C8D; margin-bottom: 5px;">NON</div> <div style="font-size: 18px; font-weight: bold; color: #16A085;">${(lifetimeNON /365).toFixed(1)}y </div> <div style="font-size: 10px; color: #7F8C8D;">${dailyEnergyNON.toFixed(3)} mAh/day</div> </div> <div> <div style="font-size: 11px; color: #7F8C8D; margin-bottom: 5px;">CON</div> <div style="font-size: 18px; font-weight: bold; color: #E67E22;">${(lifetimeCON /365).toFixed(1)}y </div> <div style="font-size: 10px; color: #7F8C8D;">${dailyEnergyCON.toFixed(3)} mAh/day</div> </div> <div> <div style="font-size: 11px; color: #7F8C8D; margin-bottom: 5px;">Hybrid</div> <div style="font-size: 18px; font-weight: bold; color: #3498DB;">${(lifetimeHybrid /365).toFixed(1)}y </div> <div style="font-size: 10px; color: #7F8C8D;">${dailyEnergyHybrid.toFixed(3)} mAh/day</div> </div> </div> </div> <div style="margin-top: 15px; padding: 12px; background: #E8F5E9; border-radius: 6px; font-size: 13px; color: #2C3E50;"> <strong>💡 Tip:</strong> ${ messageType ==="NON"?"NON messages maximize battery life but provide no delivery guarantee. Use for frequent sensor readings where occasional loss is acceptable.": messageType ==="CON"?"CON messages guarantee delivery but consume 16x more energy. Use sparingly for critical alerts only.":"Hybrid mode (95% NON, 5% CON) balances reliability and efficiency - use NON for routine readings and CON for important state changes."} </div> </div></div>`
43.4.1 Acknowledgment (ACK)
Confirms receipt of confirmable message:
May include response (piggyback)
Or just acknowledgment (response comes separately)
43.4.2 Reset (RST)
Rejects invalid message:
Unknown message ID
Message cannot be processed
Server unavailable
43.5 Message Exchange Patterns
43.6 Videos
Application Protocols Overview (from slides)
Application Protocols Overview
From Lesson 4 — placing CoAP among MQTT/HTTP/AMQP; REST patterns and trade-offs.
Protocols and REST in Practice
Protocols and REST in Practice
From Lesson 4 — practical layering and REST interactions relevant to CoAP.
43.6.1 Piggyback Response
Server responds immediately within ACK:
Figure 43.4: CoAP Piggyback Response: Response Included in ACK Message
Advantage: Single round-trip, efficient
43.6.2 Separate Response
Server needs time to process:
Figure 43.5: CoAP Separate Response: Empty ACK Followed by Delayed Response
Use when: Long processing time required
43.7 Interactive: CoAP Retransmission Timeline
Visualize how CoAP’s exponential backoff algorithm affects retransmission timing and battery life:
Show code
viewof ackTimeout = Inputs.range([1,10], {value:2,step:0.5,label:"ACK_TIMEOUT (seconds)"})viewof maxRetransmit = Inputs.range([1,8], {value:4,step:1,label:"MAX_RETRANSMIT (attempts)"})viewof randomFactor = Inputs.range([1.0,2.0], {value:1.5,step:0.1,label:"ACK random factor",width:260})// Calculate retransmission scheduleretransmissionSchedule = {const schedule = [];let cumulativeTime =0;let timeout = ackTimeout;// Initial transmission schedule.push({attempt:0,timeout:0,cumulativeTime:0,label:"Initial TX" });// Retransmissionsfor (let i =1; i <= maxRetransmit; i++) {// Add jitter to timeoutconst jitter = timeout * (1+ (randomFactor -1) *Math.random()); cumulativeTime += jitter; schedule.push({attempt: i,timeout: jitter,cumulativeTime: cumulativeTime,label:`Retry ${i}` });// Double timeout for next attempt (exponential backoff) timeout *=2; }return schedule;}// Calculate total time and energy costmaxTransmitSpan = retransmissionSchedule[retransmissionSchedule.length-1].cumulativeTimeenergyCostPerAttempt =0.272// mAs from earlier calculationtotalEnergyCost = energyCostPerAttempt * (maxRetransmit +1)html`<div style="font-family: Arial, sans-serif; max-width: 800px; margin: 20px 0;"> <div style="background: linear-gradient(135deg, #E67E22 0%, #E74C3C 100%); color: white; padding: 20px; border-radius: 8px; margin-bottom: 20px;"> <h3 style="margin: 0 0 10px 0; color: white;">CoAP Retransmission Timeline</h3> <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; margin-top: 15px;"> <div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 6px;"> <div style="font-size: 12px; opacity: 0.9; margin-bottom: 5px;">Total Attempts</div> <div style="font-size: 24px; font-weight: bold;">${maxRetransmit +1}</div> <div style="font-size: 11px; opacity: 0.8; margin-top: 5px;"> 1 initial + ${maxRetransmit} retries </div> </div> <div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 6px;"> <div style="font-size: 12px; opacity: 0.9; margin-bottom: 5px;">Total Time</div> <div style="font-size: 24px; font-weight: bold;">${maxTransmitSpan.toFixed(1)}s</div> <div style="font-size: 11px; opacity: 0.8; margin-top: 5px;"> until final timeout </div> </div> <div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 6px;"> <div style="font-size: 12px; opacity: 0.9; margin-bottom: 5px;">Energy Cost</div> <div style="font-size: 24px; font-weight: bold;">${totalEnergyCost.toFixed(2)} mAs</div> <div style="font-size: 11px; opacity: 0.8; margin-top: 5px;"> if all attempts fail </div> </div> </div> </div> <div style="background: #f8f9fa; padding: 20px; border-radius: 8px; border-left: 4px solid #E67E22;"> <h4 style="margin: 0 0 15px 0; color: #2C3E50;">Transmission Schedule</h4>${retransmissionSchedule.map((item, index) => {const barWidth = index ===0?0: (item.timeout/ maxTransmitSpan *100);const barColor = index ===0?'#16A085': index === maxRetransmit ?'#E74C3C':'#E67E22';return` <div style="margin-bottom: 12px;"> <div style="display: flex; justify-content: space-between; font-size: 12px; color: #2C3E50; margin-bottom: 4px;"> <span><strong>${item.label}</strong></span> <span>t = ${item.cumulativeTime.toFixed(2)}s</span> </div> <div style="background: #e0e0e0; height: 24px; border-radius: 4px; position: relative; overflow: hidden;"> <div style="background: ${barColor}; width: ${item.cumulativeTime/ maxTransmitSpan *100}%; height: 100%; border-radius: 4px; display: flex; align-items: center; padding: 0 8px; color: white; font-size: 11px; font-weight: 600;">${index ===0?'Send':`Wait ${item.timeout.toFixed(2)}s`} </div> </div> </div> `; }).join('')} <div style="margin-top: 20px; padding: 12px; background: #FFF3E0; border-radius: 6px; font-size: 13px; color: #2C3E50;"> <strong>⚡ Energy Impact:</strong> If all ${maxRetransmit +1} attempts fail, you've spent ${totalEnergyCost.toFixed(2)} mAs = ${(totalEnergyCost /0.017).toFixed(0)}x the energy of a successful NON message. This is why CON should be used sparingly for battery-powered devices! </div> <div style="margin-top: 10px; padding: 12px; background: #E3F2FD; border-radius: 6px; font-size: 13px; color: #2C3E50;"> <strong>🔄 Exponential Backoff:</strong> Each retry doubles the timeout (with jitter from ACK_RANDOM_FACTOR=${randomFactor.toFixed(1)}). This prevents synchronized retransmissions from overwhelming the network when multiple devices timeout simultaneously. </div> </div></div>`
Quick Review: Match & Sequence
Test your recall before the detailed knowledge checks below.
Knowledge Check: CoAP Message Types & PatternsTest Your Understanding
43.8 Knowledge Check
Test your understanding of CoAP message types and communication patterns.