Skip to main content

WhirlingBits LWM2M Client Documentation

The wb-idf-lwm2m component provides a production-ready OMA LWM2M 1.0/1.1 client for ESP-IDF projects. Built on top of , it implements the LWM2M Registration Interface and Object Model, enabling standards-compliant device management with servers such as Eclipse Leshan, ThingsBoard, or AVSystem Coiote.

  • โœ… LWM2M Registration : Register, Update, Deregister operations

  • โœ… Standard Objects : Security (/0), Server (/1), Device (/3), Connectivity Monitoring (/4), Firmware Update (/5), Location (/6), Connectivity Statistics (/7)

  • โœ… Custom Objects : Define your own objects with read/write/execute callbacks

  • โœ… DTLS Security : Pre-Shared Key and X.509 Certificate modes

  • โœ… TLV Encoding : Full encoder/decoder per OMA spec ยง6.4.3

  • โœ… SenML-JSON : Encoding for notifications and resource reads

  • โœ… Observe/Notify : Push resource changes to the server

  • โœ… OTA Firmware : Firmware Update Object with state machine

  • โœ… Value Helpers : Type-safe macros and accessor functions

  • โœ… Event-Driven : Unified event callback for all lifecycle events

  • โœ… Automatic Updates : Timer-based registration keepalive at 80% lifetime

  • wb_lwm2m.h โ€” Client init, start, stop, destroy, notify

  • wb_lwm2m_object.h โ€” Object/Resource definitions, value types, callback types, helper macros

  • wb_lwm2m_std_objects.h โ€” Factory functions for OMA standard objects (Security, Server, Device, Firmware, Location, โ€ฆ)

  • wb_lwm2m_encode.h โ€” CoRE Link-Format and SenML-JSON

  • wb_lwm2m_tlv.h โ€” TLV binary encoder/decoder

* โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
* โ”‚ User Application โ”‚
* โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
* โ”‚ wb-idf-lwm2m โ”‚
* โ”‚ โ”œโ”€โ”€ Object/Resource Model โ”‚
* โ”‚ โ”œโ”€โ”€ Registration Interface โ”‚
* โ”‚ โ”œโ”€โ”€ Link-Format / SenML Encoding โ”‚
* โ”‚ โ”œโ”€โ”€ TLV Encoder/Decoder โ”‚
* โ”‚ โ””โ”€โ”€ Lifecycle Management โ”‚
* โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
* โ”‚ wb-idf-coap-client โ”‚
* โ”‚ โ””โ”€โ”€ GET / POST / PUT / DELETE โ”‚
* โ”‚ โ””โ”€โ”€ Observe / DTLS-PSK / DTLS-PKI โ”‚
* โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
* โ”‚ libcoap (espressif/coap) โ”‚
* โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
* โ”‚ ESP-IDF (lwIP, mbedTLS, FreeRTOS) โ”‚
* โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
*

Add to your ESP-IDF project via idf_component.yml :

dependencies:
whirlingbits/wb-idf-lwm2m:
version: "*"
git: https://gitlab.whirlingbits.de/whirlingbits/wb-idf-lwm2m.git

Or clone into your project's components/ directory:

cd components
git submodule add https://gitlab.whirlingbits.de/whirlingbits/wb-idf-lwm2m.git
#include "wb_lwm2m.h"
#include "wb_lwm2m_object.h"
#include "wb_lwm2m_std_objects.h"

// 1. Create standard objects via factory functions
wb_lwm2m_object_def_t *security_obj = wb_lwm2m_create_security_object(
&(wb_lwm2m_security_info_t){
.server_uri = "coaps://server.example.com:5684",
.mode = WB_LWM2M_SEC_MODE_PSK,
.short_server_id = 1,
.pub_key_identity = (const uint8_t *)"my-device",
.pub_key_identity_len = 9,
.secret_key = psk_key,
.secret_key_len = sizeof(psk_key),
}, 0);

wb_lwm2m_object_def_t *server_obj = wb_lwm2m_create_server_object(
&(wb_lwm2m_server_info_t){
.short_server_id = 1,
.lifetime = 300,
.binding = "U",
}, 0, NULL, NULL, NULL);

wb_lwm2m_object_def_t *device_obj = wb_lwm2m_create_device_object(
&(wb_lwm2m_device_info_t){
.manufacturer = "WhirlingBits",
.model_number = "ESP32-WB-LWM2M",
.serial_number = "0001",
.binding = "U",
.firmware_version = "1.0.0",
.reboot_cb = my_reboot_cb,
}, NULL);

// 2. Create and configure the client
wb_lwm2m_client_config_t config = {
.server_uri = "coaps://server.example.com:5684",
.endpoint_name = "my-device",
.lifetime = 300,
.binding = "U",
.lwm2m_version = "1.0",
.security = WB_COAP_SECURITY_PSK,
.psk = { .identity = "my-device", .key = psk_key, .key_len = sizeof(psk_key) },
.event_handler = my_event_handler,
};

wb_lwm2m_client_handle_t lwm2m = wb_lwm2m_init(&config);

// 3. Register objects (MUST be before start)
wb_lwm2m_add_object(lwm2m, security_obj);
wb_lwm2m_add_object(lwm2m, server_obj);
wb_lwm2m_add_object(lwm2m, device_obj);

// 4. Start โ€” connects and registers with the LWM2M server
wb_lwm2m_start(lwm2m);

// 5. Periodically push telemetry
while (1) {
vTaskDelay(pdMS_TO_TICKS(30000));
if (wb_lwm2m_is_registered(lwm2m)) {
wb_lwm2m_notify(lwm2m, WB_LWM2M_OBJ_DEVICE, 0,
WB_LWM2M_RES_DEVICE_MEMORY_FREE);
}
}

// 6. Clean shutdown
wb_lwm2m_stop(lwm2m);
wb_lwm2m_destroy(lwm2m);
wb_lwm2m_destroy_std_object(security_obj);
wb_lwm2m_destroy_std_object(server_obj);
wb_lwm2m_destroy_std_object(device_obj);
ModeURI SchemeConfig
NoSeccoap://security = WB_COAP_SECURITY_NONE
PSKcoaps://security = WB_COAP_SECURITY_PSK + .psk
PKIcoaps://security = WB_COAP_SECURITY_PKI + .pki

Mode

URI Scheme

Config

NoSec

coap://

security = WB_COAP_SECURITY_NONE

PSK

coaps://

security = WB_COAP_SECURITY_PSK + .psk

PKI

coaps://

security = WB_COAP_SECURITY_PKI + .pki

The Security Object (/0) must use the matching wb_lwm2m_security_mode_t .

OptionDefaultDescription
WB_LWM2M_DEFAULT_LIFETIME86400Registration lifetime (seconds)
WB_LWM2M_DEFAULT_BINDING"U"Binding mode (U=UDP, UQ=UDP+Queue)
WB_LWM2M_DEFAULT_VERSION"1.0"LWM2M protocol version
WB_LWM2M_MAX_OBJECTS16Maximum number of registerable objects

Option

Default

Description

WB_LWM2M_DEFAULT_LIFETIME

86400

Registration lifetime (seconds)

WB_LWM2M_DEFAULT_BINDING

"U"

Binding mode (U=UDP, UQ=UDP+Queue)

WB_LWM2M_DEFAULT_VERSION

"1.0"

LWM2M protocol version

WB_LWM2M_MAX_OBJECTS

16

Maximum number of registerable objects

ServerNotes
Eclipse LeshanOpen-source reference server, great for development
ThingsBoardIoT platform with LWM2M device profiles
AVSystem CoioteCommercial cloud-based device management
WhirlingBits IoTCustom server with DTLS-PSK support

Server

Notes

Eclipse Leshan

Open-source reference server, great for development

ThingsBoard

IoT platform with LWM2M device profiles

AVSystem Coiote

Commercial cloud-based device management

WhirlingBits IoT

Custom server with DTLS-PSK support

  • Client-initiated only : Server-initiated Read/Write/Execute (where the LWM2M server sends CoAP requests to the device) is not yet supported.

  • No Bootstrap : LWM2M Bootstrap interface is not implemented.

  • No Block-wise OTA : Firmware Update object execution is application-level.

  • ESP-IDF Version: 5.0 or higher

  • Dependencies: wb-idf-coap-client, espressif/coap >= 4.3.4

  • Supported SoCs: ESP32, ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C6

  • Network: WiFi or Ethernet (IP connectivity required)

  • License: Apache License 2.0

  • GitLab Repository

  • Issue Tracker

  • wb-idf-coap-client

  • Examples

Copyright (c) 2024 WhirlingBits

Licensed under the Apache License, Version 2.0. See LICENSE file in the project root for details.

Componentsโ€‹

Client Lifecycleโ€‹

LWM2M client initialization, registration, and runtime management.

Object / Resource Modelโ€‹

LWM2M data model with typed resources and callback-driven access.

Standard Object Factoryโ€‹

Pre-built factory functions for OMA LWM2M standard objects.

Encoding Helpersโ€‹

CoRE Link-Format and SenML-JSON encoding for LWM2M payloads.