Protokol

CoAP Protocol untuk IoT

Panduan lengkap Constrained Application Protocol (CoAP) — protokol ringan berbasis REST yang dirancang khusus untuk perangkat IoT dengan sumber daya terbatas, mencakup request/response, observe pattern, block transfer, dan keamanan DTLS

1. Apa Itu CoAP?

CoAP (Constrained Application Protocol) adalah protokol aplikasi ringan yang didefinisikan dalam RFC 7252, dirancang khusus untuk constrained devices dan constrained networks dalam ekosistem Internet of Things (IoT). CoAP menyediakan model request/response yang mirip dengan HTTP, tetapi dioptimasi untuk perangkat dengan RAM, CPU, dan daya baterai yang sangat terbatas.

Mengapa Tidak Langsung Pakai HTTP?

Parameter HTTP/1.1 CoAP
Transport LayerTCPUDP
Overhead per request~200+ bytes header~10-20 bytes header
Parsing complexityText-based, mahalBinary, sangat ringan
Minimum RAM~50-100 KB~10 KB
Multicast supportTidakYa (built-in)
Asynchronous messagingTidak nativeConfirmable/Non-confirmable
TLS/DTLSTLS (TCP)DTLS (UDP)
Port default80 / 4435683 (CoAP) / 5684 (CoAPS)
💡 Kapan Menggunakan CoAP?

CoAP ideal untuk skenario di mana perangkat IoT perlu berkomunikasi dengan server/middleware melalui jaringan constrained (LPWAN, 6LoWPAN, BLE). Contoh: sensor suhu di pertanian, smart meter, wearable health monitor. Jika perangkat Anda sudah punya WiFi stabil dan resource cukup, MQTT atau HTTP mungkin lebih sesuai.

CoAP dalam Stack Protokol IoT

CoAP berada di layer aplikasi dan menggunakan UDP sebagai transport. Pada jaringan 6LoWPAN, CoAP dapat berjalan di atas IEEE 802.15.4 dengan bantuan adaptasi layer 6LoWPAN. Dengan demikian, CoAP dapat menjangkau perangkat di edge network yang sangat constrained.

Text
┌─────────────────────────────────────┐
│         CoAP (Application)          │  ← RFC 7252
├─────────────────────────────────────┤
│              UDP                    │  ← Transport
├─────────────────────────────────────┤
│         IPv6 / 6LoWPAN              │  ← Network
├─────────────────────────────────────┤
│      IEEE 802.15.4 / BLE           │  ← Link
└─────────────────────────────────────┘

2. Arsitektur & Message Model

CoAP menggunakan arsitektur client-server dengan komunikasi asynchronous. Setiap pesan CoAP dikirim dalam satu datagram UDP. CoAP mendefinisikan dua jenis pesan utama: Confirmable (CON) dan Non-confirmable (NON).

CoAP Message Types

Type Kode Fungsi Contoh Penggunaan
Confirmable (CON)0Pesan yang memerlukan acknowledgmentRequest penting, data kritis
Non-confirmable (NON)1Pesan tanpa ACK, fire-and-forgetTelemetry berkala, sensor reading
Acknowledgment (ACK)2Konfirmasi penerimaan CON messageResponse ke CON request
Reset (RST)3Menolak pesan, endpoint tidak mengenali contextError handling

CoAP Message Format

Setiap pesan CoAP memiliki header tetap 4 byte yang sangat ringkas dibandingkan HTTP header yang bisa ratusan byte:

Text
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Ver| T |  TKL  |      Code     |         Message ID            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   Token (0-8 bytes, sesuai TKL) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   Options ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 1 1 1 1 1 1 1|    Payload (jika ada) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Ver   = Version (2 bit, selalu 01 untuk CoAP v1)
T     = Type (2 bit: CON=0, NON=1, ACK=2, RST=3)
TKL   = Token Length (4 bit: 0-8 bytes)
Code  = Request/Response code (8 bit)
MsgID = Message ID (16 bit, untuk deduplikasi)

CoAP URIs dan Content-Formats

CoAP menggunakan URI scheme coap:// (unencrypted) dan coaps:// (DTLS-encrypted). Format konten diidentifikasi dengan numeric Content-Format codes, bukan MIME types text:

Text
# Contoh CoAP URIs
coap://sensor.example.com/temperature
coap://[::1]:5683/led/status
coaps://gateway.local/humidity

# Content-Format Codes (IANA registered)
0   - text/plain; charset=utf-8
40  - application/link-format
41  - application/xml
42  - application/octet-stream
47  - application/exi
50  - application/json
60  - application/cbor

3. Request/Response Model

Model request/response CoAP mirip dengan HTTP, menggunakan method yang sama: GET, POST, PUT, DELETE. Namun, request dan response tidak harus dalam satu siklus TCP — karena CoAP berjalan di atas UDP, ada mekanisme khusus untuk menangani reliability.

CoAP Method Codes

Method Code Fungsi
GET0.01Mengambil resource representation
POST0.02Membuat resource baru atau menjalankan prosedur
PUT0.03Memperbarui atau membuat resource
DELETE0.04Menghapus resource
FETCH0.05Mengambil resource dengan request body (RFC 8132)
PATCH0.06Partial update (RFC 8132)
iPATCH0.07Idempotent partial update (RFC 8132)

Response Codes

CoAP response codes menggunakan format class.detail (mirip HTTP status codes):

Text
# Success Responses (2.xx)
2.01 - Created
2.02 - Deleted
2.03 - Valid (cache masih valid)
2.04 - Changed
2.05 - Content (equivalent HTTP 200 OK)

# Client Error Responses (4.xx)
4.00 - Bad Request
4.01 - Unauthorized
4.02 - Bad Option
4.03 - Forbidden
4.04 - Not Found
4.05 - Method Not Allowed
4.06 - Not Acceptable
4.08 - Request Entity Incomplete
4.12 - Precondition Failed
4.13 - Request Entity Too Large
4.15 - Unsupported Content-Format

# Server Error Responses (5.xx)
5.00 - Internal Server Error
5.01 - Not Implemented
5.02 - Bad Gateway
5.03 - Service Unavailable
5.04 - Gateway Timeout

Contoh Komunikasi CoAP

Text
# === Skenario: Client membaca sensor suhu ===

Client                                          Server
  |                                               |
  |--- CON [0x7a21] GET /temperature  -------->   |
  |                                               |
  |<-- ACK [0x7a21] 2.05 Content {"temp":23.5}   |
  |                                               |

# === Skenario: Multicast discovery ===

Client (multicast ke ff02::1)                     Server A & B
  |                                               |
  |--- NON [0x7a22] GET /.well-known/core ------->|
  |                                               |
  |<-- NON [0x7a22] 2.05 Content [A's resources]  |
  |<-- NON [0x7a22] 2.05 Content [B's resources]  |

# === Skenario: Reliable messaging dengan retransmit ===

Client                                          Server
  |                                               |
  |--- CON [0x1234] PUT /led  Payload: "on" --->  |
  |    (timeout, no ACK received)                 |
  |--- CON [0x1234] PUT /led  Payload: "on" --->  | (retransmit)
  |                                               |
  |<-- ACK [0x1234] 2.04 Changed                  |
⚠️ Reliability di Atas UDP

CoAP implementasi reliability melalui Confirmable messages (CON) dengan exponential backoff retransmission. Jika CON message tidak mendapat ACK dalam ACK_TIMEOUT (default 2 detik), pesan di-retransmit hingga MAX_RETRANSMIT kali (default 4). Timeout dikalikan dengan ACK_RANDOM_FACTOR untuk menghindari retransmission storms.

4. Observe Pattern

Observe pattern (RFC 7641) memungkinkan client untuk mendaftar sebagai observer pada suatu resource. Server akan mengirimkan notifikasi setiap kali resource berubah, tanpa client perlu melakukan polling berkala. Ini sangat menghemat bandwidth dan baterai pada perangkat IoT.

Cara Kerja Observe

Text
# Client mendaftar sebagai observer dengan menambahkan Observe option

Client                                          Server
  |                                               |
  |--- CON [0x7a21] GET /temperature              |
  |    Observe: 0 (register)  ----------------->  |
  |                                               |
  |<-- ACK [0x7a21] 2.05 Content                  |
  |    Observe: 1   {"temp": 23.5}                |
  |                                               |
  |    ... suhu berubah ...                       |
  |                                               |
  |<-- CON [0x7a22] 2.05 Content                  |
  |    Observe: 2   {"temp": 24.1}                |
  |--- ACK [0x7a22]  ---------------------------> |
  |                                               |
  |    ... suhu berubah lagi ...                  |
  |                                               |
  |<-- NON [0x7a23] 2.05 Content                  |
  |    Observe: 3   {"temp": 23.8}                |
  |                                               |

Implementasi Observe di Python

Python
import asyncio
from aiocoap import *

async def observe_temperature():
    """Register sebagai observer pada resource /temperature"""
    protocol = await Context.create_client_context()

    request = Message(
        code=GET,
        uri='coap://sensor.example.com/temperature',
        observe=0  # Register sebagai observer
    )

    # Kirim request pertama dan dapatkan initial response
    requester = protocol.request(request)
    first_response = await requester.response
    print(f"Suhu awal: {first_response.payload.decode()}")

    # Loop untuk menerima notifikasi berikutnya
    async for response in requester.observation:
        print(f"Suhu berubah: {response.payload.decode()}")

        # Unsubscribe jika sudah tidak perlu
        if float(response.payload.decode()) > 30.0:
            requester.observation.cancel()
            break

asyncio.run(observe_temperature())

Observe Relationship Lifecycle

Server menyimpan daftar observer untuk setiap resource. Observer bisa berhenti berlangganan dengan dua cara: mengirim GET request dengan Observe option bernilai 1 (deregister), atau mengirim RST ke notifikasi terakhir dari server. Server juga bisa mengakhiri observe relationship jika resource dihapus atau terjadi error.

💡 Observe vs Polling

Dengan polling GET setiap 5 detik, perangkat IoT mengirim 17,280 request per hari. Dengan Observe, perangkat hanya mengirim 1 request registrasi dan menerima notifikasi saat ada perubahan. Pada sensor yang jarang berubah, ini bisa menghemat 99% bandwidth dan baterai.

5. Block Transfer

Ukuran payload default CoAP dibatasi oleh maximum UDP datagram size. Pada jaringan 6LoWPAN (IEEE 802.15.4), payload efektif hanya sekitar 60-80 bytes. Untuk mengatasi keterbatasan ini, CoAP mendefinisikan Block-Wise Transfer (RFC 7959).

Block Option

Text
# Block Option encoding (variable length: 1-3 bytes)
# Format: NUM.M.SIZE
#
# NUM  = Block number (4/12/20 bit) — sequential numbering
# M    = More bit (1 bit) — 1 jika ada blok berikutnya, 0 jika terakhir
# SIZE = Block size exponent (3 bit) — 2^(4+SZX) bytes
#
# Block Size mapping:
# SZX=0 → 16 bytes    SZX=4 → 256 bytes
# SZX=1 → 32 bytes    SZX=5 → 512 bytes
# SZX=2 → 64 bytes    SZX=6 → 1024 bytes
# SZX=3 → 128 bytes   SZX=7 → reserved

# Contoh transfer file 1024 bytes dengan block size 256 bytes:
# Block 0: NUM=0, M=1, SZX=4  → "0M4" = bytes 0-255
# Block 1: NUM=1, M=1, SZX=4  → "1M4" → bytes 256-511
# Block 2: NUM=2, M=1, SZX=4  → "2M4" → bytes 512-767
# Block 3: NUM=3, M=0, SZX=4  → "3_4" → bytes 768-1023 (terakhir)

Block-Wise Transfer Flow

Text
Client                                          Server
  |                                               |
  |--- CON GET /firmware                         |
  |    Block2: 0/0/6 (NUM=0, M=0, SZX=6) --->   |
  |    (minta blok pertama, size 1024)            |
  |                                               |
  |<-- ACK 2.05 Content                           |
  |    Block2: 0/1/6 (M=1, ada lagi)             |
  |    [bytes 0-1023]                             |
  |                                               |
  |--- CON GET /firmware                         |
  |    Block2: 1/0/6  ----------------------->   |
  |                                               |
  |<-- ACK 2.05 Content                           |
  |    Block2: 1/1/6                             |
  |    [bytes 1024-2047]                          |
  |                                               |
  |--- CON GET /firmware                         |
  |    Block2: 2/0/6  ----------------------->   |
  |                                               |
  |<-- ACK 2.05 Content                           |
  |    Block2: 2/0/6 (M=0, selesai)              |
  |    [bytes 2048-3000]                          |

Block1 untuk Upload

Selain Block2 untuk download, CoAP juga mendefinisikan Block1 untuk upload data besar ke server. Ini berguna untuk firmware update (OTA), upload konfigurasi, atau pengiriman batch data sensor.

Python
import asyncio
from aiocoap import *
from aiocoap.numbers import ContentFormat

async def upload_firmware():
    """Upload firmware menggunakan Block1 transfer"""
    context = await Context.create_client_context()

    firmware_data = open('firmware.bin', 'rb').read()
    block_size = 1024
    total_blocks = (len(firmware_data) + block_size - 1) // block_size

    for i in range(total_blocks):
        start = i * block_size
        end = min(start + block_size, len(firmware_data))
        chunk = firmware_data[start:end]

        request = Message(
            code=PUT,
            uri='coap://device.local/firmware',
            payload=chunk,
            content_format=ContentFormat.OCTETSTREAM
        )

        # Set Block1 option: NUM/M/SZX
        is_last = (i == total_blocks - 1)
        request.remote.opt.block1 = (i, not is_last, 6)

        response = await context.request(request).response
        print(f"Block {i+1}/{total_blocks}: {response.code}")

    print("Upload selesai!")

asyncio.run(upload_firmware())

6. DTLS Security

Karena CoAP menggunakan UDP (bukan TCP), protokol keamanan standar TLS tidak bisa digunakan. Sebagai gantinya, CoAP menggunakan DTLS (Datagram Transport Layer Security) — versi TLS yang diadaptasi untuk datagram-oriented transport. CoAP dengan DTLS disebut CoAPS dan berjalan pada port 5684.

DTLS Mode pada CoAP

Mode Deskripsi Kegunaan
NoSecTanpa keamanan, raw CoAPTesting, trusted network
PreSharedKey (PSK)Kunci simetris yang sudah diketahui sebelumnyaIoT device-to-gateway
RawPublicKey (RPK)Pasangan kunci publik/privat tanpa sertifikatConstrained devices
Certificate (X.509)Sertifikat X.509 standarProduction, enterprise IoT

DTLS Handshake pada CoAP

Text
# DTLS 1.2 Handshake (mirip TLS tetapi di atas UDP)

Client (IoT Device)                    Server (Gateway)
  |                                        |
  |--- ClientHello  --------------------> |
  |<-- HelloVerifyRequest (cookie)        |
  |--- ClientHello + Cookie  -----------> |
  |<-- ServerHello + Certificate          |
  |<-- ServerKeyExchange                  |
  |<── ServerHelloDone                    |
  |--- ClientKeyExchange                  |
  |--- ChangeCipherSpec                   |
  |--- Finished  ────────────────────────>|
  |<── ChangeCipherSpec                   |
  |<── Finished                           |
  |                                        |
  |==== Encrypted CoAP messages =========>|

Implementasi CoAPS dengan PSK

Python
import asyncio
from aiocoap import *

async def secure_request():
    """Mengirim CoAP request dengan DTLS (PreSharedKey)"""
    context = await Context.create_client_context()

    # Setup DTLS credentials
    # Untuk PSK, client dan server harus share identity + key
    # Implementation-specific setup via aiocoap credentials
    request = Message(
        code=GET,
        uri='coaps://gateway.example.com:5684/sensors/data'
    )

    response = await context.request(request).response
    print(f"Status: {response.code}")
    print(f"Data: {response.payload.decode()}")

asyncio.run(secure_request())
⚠️ DTLS dan NAT

DTLS menghadapi tantangan pada jaringan dengan NAT karena UDP tidak memiliki koneksi persistent seperti TCP. Solusinya adalah menggunakan DTLS Connection ID (CID) yang memungkinkan koneksi tetap hidup meski alamat IP/port berubah. Ini penting untuk perangkat IoT mobile atau yang sering sleep/wake.

7. CoAP vs MQTT vs HTTP

Memilih protokol yang tepat untuk proyek IoT bergantung pada karakteristik jaringan, perangkat, dan use case. Berikut perbandingan komprehensif:

Aspek CoAP MQTT HTTP/REST
ModelRequest/Response + ObservePublish/SubscribeRequest/Response
TransportUDPTCPTCP
OverheadSangat rendah (4 byte header)Rendah (2 byte minimum)Tinggi (text headers)
ReliabilityCON/ACK mechanismQoS 0, 1, 2TCP built-in
Pattern1-to-1, 1-to-many (observe)Many-to-many (broker)1-to-1
SecurityDTLSTLSTLS
Web FriendlyYa (REST semantics)Tidak langsungYa (native web)
Best ForResource-constrained devices, RESTful IoTReal-time messaging, telemetryWeb API, client-server

8. Implementasi dengan libcoap

libcoap adalah library C yang populer untuk implementasi CoAP pada embedded systems. Library ini mendukung CoAP RFC 7252, Observe, Block Transfer, dan DTLS. Berikut contoh implementasi server CoAP sederhana:

CoAP Server dengan Python (aiocoap)

Python
import asyncio
import json
import datetime
import aiocoap
import aiocoap.resource as resource

class TemperatureResource(resource.ObservableResource):
    """Resource /temperature dengan Observe support"""
    def __init__(self):
        super().__init__()
        self.temperature = 23.5
        self.notify()

    def notify(self):
        self.updated_state()
        # Schedule next update setiap 10 detik
        asyncio.get_event_loop().call_later(10, self.notify)

    async def render_get(self, request):
        data = json.dumps({
            "temperature": self.temperature,
            "unit": "celsius",
            "timestamp": datetime.datetime.now().isoformat()
        })
        return aiocoap.Message(
            payload=data.encode('utf-8'),
            content_format=50  # application/json
        )

    async def render_put(self, request):
        """Update temperature via PUT"""
        payload = json.loads(request.payload.decode())
        self.temperature = payload.get("temperature", self.temperature)
        return aiocoap.Message(
            code=aiocoap.CHANGED,
            payload=json.dumps({"status": "ok"}).encode()
        )

class DeviceInfoResource(resource.Resource):
    """Resource /info — static device information"""
    async def render_get(self, request):
        info = {
            "device": "ESP32-Sensor-01",
            "firmware": "1.2.3",
            "uptime": "24h 30m",
            "battery": "87%"
        }
        return aiocoap.Message(
            payload=json.dumps(info).encode(),
            content_format=50
        )

# Build resource tree
root = resource.Site()
root.add_resource(['temperature'], TemperatureResource())
root.add_resource(['info'], DeviceInfoResource())
root.add_resource(['.well-known', 'core'],
    resource.WKCResource(root.get_resources_as_linkheader))

# Start CoAP server
asyncio.Task(aiocoap.Context.create_server_context(root))
asyncio.get_event_loop().run_forever()

CoAP Client di ESP32 (Arduino)

C++
#include <WiFi.h>
#include <WiFiUdp.h>
#include <coap-simple.h>

const char* ssid = "MyNetwork";
const char* password = "MyPassword";

WiFiUDP udp;
Coap coap(udp);

// Callback saat menerima response
void callback_response(CoapPacket &packet, IPAddress ip, int port) {
    char p[packet.payloadlen + 1];
    memcpy(p, packet.payload, packet.payloadlen);
    p[packet.payloadlen] = '\0';

    Serial.print("Response dari ");
    Serial.print(ip);
    Serial.print(": ");
    Serial.println(p);
}

void setup() {
    Serial.begin(115200);
    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("WiFi connected!");

    // Register response callback
    coap.response(callback_response);

    // Start CoAP client
    coap.start();

    // Kirim GET request ke server CoAP
    coap.get(IPAddress(192, 168, 1, 100), 5683, "temperature");
}

void loop() {
    coap.loop();

    // Kirim request setiap 30 detik
    static unsigned long lastTime = 0;
    if (millis() - lastTime > 30000) {
        lastTime = millis();
        coap.get(IPAddress(192, 168, 1, 100), 5683, "temperature");
    }
}
📚 Library CoAP Populer
  • libcoap (C) — Library C mature, banyak digunakan di embedded
  • aiocoap (Python) — Async Python implementation, bagus untuk prototyping
  • Eclipse Californium (Java) — Enterprise-grade Java implementation
  • CoAP.js (Node.js) — JavaScript implementation untuk server dan client
  • libcoap-minimal (C) — Untuk microcontroller sangat constrained

Quiz Pemahaman

Pertanyaan 1: Berapa ukuran header tetap minimum CoAP?

a) 2 byte
b) 4 byte
c) 8 byte
d) 16 byte

Pertanyaan 2: Message type apa yang digunakan untuk reliable messaging di CoAP?

a) Non-confirmable (NON)
b) Confirmable (CON)
c) Reset (RST)
d) Acknowledgment (ACK)

Pertanyaan 3: Untuk apa Observe pattern digunakan di CoAP?

a) Mengenkripsi komunikasi
b) Melakukan handshake awal
c) Menerima notifikasi saat resource berubah tanpa polling
d) Mengompresi payload

Pertanyaan 4: Protokol keamanan apa yang digunakan CoAP (CoAPS)?

a) TLS 1.3
b) SSH
c) IPsec
d) DTLS

Pertanyaan 5: Berapa ukuran payload efektif CoAP pada jaringan 6LoWPAN (IEEE 802.15.4)?

a) 60-80 bytes
b) 256 bytes
c) 1024 bytes
d) 65535 bytes
🔍 Zoom
100%
🎨 Tema