1.. _lwm2m_interface: 2 3Lightweight M2M (LWM2M) 4####################### 5 6.. contents:: 7 :local: 8 :depth: 2 9 10Overview 11******** 12 13Lightweight Machine to Machine (LwM2M) is an application layer protocol 14designed with device management, data reporting and device actuation in mind. 15Based on CoAP/UDP, `LwM2M`_ is a 16`standard <http://openmobilealliance.org/release/LightweightM2M/>`_ defined by 17the Open Mobile Alliance and suitable for constrained devices by its use of 18CoAP packet-size optimization and a simple, stateless flow that supports a 19REST API. 20 21One of the key differences between LwM2M and CoAP is that an LwM2M client 22initiates the connection to an LwM2M server. The server can then use the 23REST API to manage various interfaces with the client. 24 25LwM2M uses a simple resource model with the core set of objects and resources 26defined in the specification. 27 28Example LwM2M object and resources: Device 29****************************************** 30 31*Object definition* 32 33.. list-table:: 34 :header-rows: 1 35 36 * - Object ID 37 - Name 38 - Instance 39 - Mandatory 40 41 * - 3 42 - Device 43 - Single 44 - Mandatory 45 46*Resource definitions* 47 48``* R=Read, W=Write, E=Execute`` 49 50.. list-table:: 51 :header-rows: 1 52 53 * - ID 54 - Name 55 - OP\* 56 - Instance 57 - Mandatory 58 - Type 59 60 * - 0 61 - Manufacturer 62 - R 63 - Single 64 - Optional 65 - String 66 67 * - 1 68 - Model 69 - R 70 - Single 71 - Optional 72 - String 73 74 * - 2 75 - Serial number 76 - R 77 - Single 78 - Optional 79 - String 80 81 * - 3 82 - Firmware version 83 - R 84 - Single 85 - Optional 86 - String 87 88 * - 4 89 - Reboot 90 - E 91 - Single 92 - Mandatory 93 - 94 95 * - 5 96 - Factory Reset 97 - E 98 - Single 99 - Optional 100 - 101 102 * - 6 103 - Available Power Sources 104 - R 105 - Multiple 106 - Optional 107 - Integer 0-7 108 109 * - 7 110 - Power Source Voltage (mV) 111 - R 112 - Multiple 113 - Optional 114 - Integer 115 116 * - 8 117 - Power Source Current (mA) 118 - R 119 - Multiple 120 - Optional 121 - Integer 122 123 * - 9 124 - Battery Level % 125 - R 126 - Single 127 - Optional 128 - Integer 129 130 * - 10 131 - Memory Free (Kb) 132 - R 133 - Single 134 - Optional 135 - Integer 136 137 * - 11 138 - Error Code 139 - R 140 - Multiple 141 - Optional 142 - Integer 0-8 143 144 * - 12 145 - Reset Error 146 - E 147 - Single 148 - Optional 149 - 150 151 * - 13 152 - Current Time 153 - RW 154 - Single 155 - Optional 156 - Time 157 158 * - 14 159 - UTC Offset 160 - RW 161 - Single 162 - Optional 163 - String 164 165 * - 15 166 - Timezone 167 - RW 168 - Single 169 - Optional 170 - String 171 172 * - 16 173 - Supported Binding 174 - R 175 - Single 176 - Mandatory 177 - String 178 179 * - 17 180 - Device Type 181 - R 182 - Single 183 - Optional 184 - String 185 186 * - 18 187 - Hardware Version 188 - R 189 - Single 190 - Optional 191 - String 192 193 * - 19 194 - Software Version 195 - R 196 - Single 197 - Optional 198 - String 199 200 * - 20 201 - Battery Status 202 - R 203 - Single 204 - Optional 205 - Integer 0-6 206 207 * - 21 208 - Memory Total (Kb) 209 - R 210 - Single 211 - Optional 212 - Integer 213 214 * - 22 215 - ExtDevInfo 216 - R 217 - Multiple 218 - Optional 219 - ObjLnk 220 221The server could query the ``Manufacturer`` resource for ``Device`` object 222instance 0 (the default and only instance) by sending a ``READ 3/0/0`` 223operation to the client. 224 225The full list of registered objects and resource IDs can be found in the 226`LwM2M registry`_. 227 228Zephyr's LwM2M library lives in the :zephyr_file:`subsys/net/lib/lwm2m`, with a 229client sample in :zephyr_file:`samples/net/lwm2m_client`. For more information 230about the provided sample see: :zephyr:code-sample:`lwm2m-client`. The sample can be 231configured to use normal unsecure network sockets or sockets secured via DTLS. 232 233The Zephyr LwM2M library implements the following items: 234 235* engine to process networking events and core functions 236* RD client which performs BOOTSTRAP and REGISTRATION functions 237* SenML CBOR, SenML JSON, CBOR, TLV, JSON, and plain text formatting functions 238* LwM2M Technical Specification Enabler objects such as Security, Server, 239 Device, Firmware Update, etc. 240* Extended IPSO objects such as Light Control, Temperature Sensor, and Timer 241 242By default, the library implements `LwM2M specification 1.0.2`_ and can be set to 243`LwM2M specification 1.1.1`_ with a Kconfig option. 244 245For more information about LwM2M visit `OMA Specworks LwM2M`_. 246 247Sample usage 248************ 249 250To use the LwM2M library, start by creating an LwM2M client context 251:c:struct:`lwm2m_ctx` structure: 252 253.. code-block:: c 254 255 /* LwM2M client context */ 256 static struct lwm2m_ctx client; 257 258Create callback functions for LwM2M resource executions: 259 260.. code-block:: c 261 262 static int device_reboot_cb(uint16_t obj_inst_id, uint8_t *args, 263 uint16_t args_len) 264 { 265 LOG_INF("Device rebooting."); 266 LOG_PANIC(); 267 sys_reboot(0); 268 return 0; /* won't reach this */ 269 } 270 271The LwM2M RD client can send events back to the sample. To receive those 272events, setup a callback function: 273 274.. code-block:: c 275 276 static void rd_client_event(struct lwm2m_ctx *client, 277 enum lwm2m_rd_client_event client_event) 278 { 279 switch (client_event) { 280 281 case LWM2M_RD_CLIENT_EVENT_NONE: 282 /* do nothing */ 283 break; 284 285 case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE: 286 LOG_DBG("Bootstrap registration failure!"); 287 break; 288 289 case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_COMPLETE: 290 LOG_DBG("Bootstrap registration complete"); 291 break; 292 293 case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_TRANSFER_COMPLETE: 294 LOG_DBG("Bootstrap transfer complete"); 295 break; 296 297 case LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE: 298 LOG_DBG("Registration failure!"); 299 break; 300 301 case LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE: 302 LOG_DBG("Registration complete"); 303 break; 304 305 case LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT: 306 LOG_DBG("Registration timeout!"); 307 break; 308 309 case LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE: 310 LOG_DBG("Registration update complete"); 311 break; 312 313 case LWM2M_RD_CLIENT_EVENT_DEREGISTER_FAILURE: 314 LOG_DBG("Deregister failure!"); 315 break; 316 317 case LWM2M_RD_CLIENT_EVENT_DISCONNECT: 318 LOG_DBG("Disconnected"); 319 break; 320 321 case LWM2M_RD_CLIENT_EVENT_REG_UPDATE: 322 LOG_DBG("Registration update"); 323 break; 324 325 case LWM2M_RD_CLIENT_EVENT_DEREGISTER: 326 LOG_DBG("Deregistration client"); 327 break; 328 329 } 330 } 331 332Next we assign ``Security`` resource values to let the client know where and how 333to connect as well as set the ``Manufacturer`` and ``Reboot`` resources in the 334``Device`` object with some data and the callback we defined above: 335 336.. code-block:: c 337 338 /* 339 * Server URL of default Security object = 0/0/0 340 * Use leshan.eclipse.org server IP (5.39.83.206) for connection 341 */ 342 lwm2m_set_string(&LWM2M_OBJ(0, 0, 0), "coap://5.39.83.206"); 343 344 /* 345 * Security Mode of default Security object = 0/0/2 346 * 3 = NoSec mode (no security beware!) 347 */ 348 lwm2m_set_u8(&LWM2M_OBJ(0, 0, 2), 3); 349 350 #define CLIENT_MANUFACTURER "Zephyr Manufacturer" 351 352 /* 353 * Manufacturer resource of Device object = 3/0/0 354 * We use lwm2m_set_res_data() function to set a pointer to the 355 * CLIENT_MANUFACTURER string. 356 * Note the LWM2M_RES_DATA_FLAG_RO flag which stops the engine from 357 * trying to assign a new value to the buffer. 358 */ 359 lwm2m_set_res_data(&LWM2M_OBJ(3, 0, 0), CLIENT_MANUFACTURER, 360 sizeof(CLIENT_MANUFACTURER), 361 LWM2M_RES_DATA_FLAG_RO); 362 363 /* Reboot resource of Device object = 3/0/4 */ 364 lwm2m_register_exec_callback(&LWM2M_OBJ(3, 0, 4), device_reboot_cb); 365 366Lastly, we start the LwM2M RD client (which in turn starts the LwM2M engine). 367The second parameter of :c:func:`lwm2m_rd_client_start` is the client 368endpoint name. This is important as it needs to be unique per LwM2M server: 369 370.. code-block:: c 371 372 (void)memset(&client, 0x0, sizeof(client)); 373 lwm2m_rd_client_start(&client, "unique-endpoint-name", 0, rd_client_event); 374 375.. _lwm2m_security: 376 377LwM2M security modes 378******************** 379 380The Zephyr LwM2M library can be used either without security or use DTLS to secure the communication channel. 381When using DTLS with the LwM2M engine, PSK (Pre-Shared Key) and X.509 certificates are the security modes that can be used to secure the communication. 382The engine uses LwM2M Security object (Id 0) to read the stored credentials and feed keys from the security object into 383the TLS credential subsystem, see :ref:`secure sockets documentation <secure_sockets_interface>`. 384Enable the :kconfig:option:`CONFIG_LWM2M_DTLS_SUPPORT` Kconfig option to use the security. 385 386Depending on the selected mode, the security object must contain following data: 387 388PSK 389 Security Mode (Resource ID 2) set to zero (Pre-Shared Key mode). 390 Identity (Resource ID 3) contains PSK ID in binary form. 391 Secret key (Resource ID 5) contains the PSK key in binary form. 392 If the key or identity is provided as a hex string, it must be converted to binary before storing into the security object. 393 394X509 395 When X509 certificates are used, set Security Mode (ID 2) to ``2`` (Certificate mode). 396 Identity (ID 3) is used to store the client certificate and Secret key (ID 5) must have a private key associated with the certificate. 397 Server Public Key resource (ID 4) must contain a server certificate or CA certificate used to sign the certificate chain. 398 If the :kconfig:option:`CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT` Kconfig option is enabled, certificates and private key can be entered in PEM format. 399 Otherwise, they must be in binary DER format. 400 401NoSec 402 When no security is used, set Security Mode (Resource ID 2) to ``3`` (NoSec). 403 404In all modes, Server URI resource (ID 0) must contain the full URI for the target server. 405When DNS names are used, the DNS resolver must be enabled. 406 407LwM2M stack provides callbacks in the :c:struct:`lwm2m_ctx` structure. 408They are used to feed keys from the LwM2M security object into the TLS credential subsystem. 409By default, these callbacks can be left as NULL pointers, in which case default callbacks are used. 410When an external TLS stack, or non-default socket options are required, you can overwrite the :c:func:`lwm2m_ctx.load_credentials` or :c:func:`lwm2m_ctx.set_socketoptions` callbacks. 411 412An example of setting up the security object for PSK mode: 413 414.. code-block:: c 415 416 /* "000102030405060708090a0b0c0d0e0f" */ 417 static unsigned char client_psk[] = { 418 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 419 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f 420 }; 421 422 static const char client_identity[] = "Client_identity"; 423 424 lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 0), "coaps://lwm2m.example.com"); 425 lwm2m_set_u8(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 2), LWM2M_SECURITY_PSK); 426 /* Set the client identity as a string, but this could be binary as well */ 427 lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 3), client_identity); 428 /* Set the client pre-shared key (PSK) */ 429 lwm2m_set_opaque(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 5), client_psk, sizeof(client_psk)); 430 431An example of setting up the security object for X509 certificate mode: 432 433.. code-block:: c 434 435 static const char certificate[] = "-----BEGIN CERTIFICATE-----\nMIIB6jCCAY+gAw..."; 436 static const char key[] = "-----BEGIN EC PRIVATE KEY-----\nMHcCAQ..."; 437 static const char root_ca[] = "-----BEGIN CERTIFICATE-----\nMIIBaz..."; 438 439 lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 0), "coaps://lwm2m.example.com"); 440 lwm2m_set_u8(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 2), LWM2M_SECURITY_CERT); 441 lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 3), certificate); 442 lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 5), key); 443 lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 5), root_ca); 444 445Before calling :c:func:`lwm2m_rd_client_start` assign the tls_tag # where the 446LwM2M library should store the DTLS information prior to connection (normally a 447value of 1 is ok here). 448 449.. code-block:: c 450 451 (void)memset(&client, 0x0, sizeof(client)); 452 client.tls_tag = 1; /* <---- */ 453 lwm2m_rd_client_start(&client, "endpoint-name", 0, rd_client_event); 454 455For a more detailed LwM2M client sample see: :zephyr:code-sample:`lwm2m-client`. 456 457Multi-thread usage 458****************** 459Writing a value to a resource can be done using functions like lwm2m_set_u8. When writing 460to multiple resources, the function lwm2m_registry_lock will ensure that the 461client halts until all writing operations are finished: 462 463.. code-block:: c 464 465 lwm2m_registry_lock(); 466 lwm2m_set_u32(&LWM2M_OBJ(1, 0, 1), 60); 467 lwm2m_set_u8(&LWM2M_OBJ(5, 0, 3), 0); 468 lwm2m_set_f64(&LWM2M_OBJ(3303, 0, 5700), value); 469 lwm2m_registry_unlock(); 470 471This is especially useful if the server is composite-observing the resources being 472written to. Locking will then ensure that the client only updates and sends notifications 473to the server after all operations are done, resulting in fewer messages in general. 474 475Support for time series data 476**************************** 477 478LwM2M version 1.1 adds support for SenML CBOR and SenML JSON data formats. These data formats add 479support for time series data. Time series formats can be used for READ, NOTIFY and SEND operations. 480When data cache is enabled for a resource, each write will create a timestamped entry in a cache, 481and its content is then returned as a content in in READ, NOTIFY or SEND operation for a given 482resource. 483 484Data cache is only supported for resources with a fixed data size. 485 486Supported resource types: 487 488* Signed and unsigned 8-64-bit integers 489* Float 490* Boolean 491 492Enabling and configuring 493======================== 494 495Enable data cache by selecting :kconfig:option:`CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT`. 496Application needs to allocate an array of :c:struct:`lwm2m_time_series_elem` structures and then 497enable the cache by calling :c:func:`lwm2m_engine_enable_cache` for a given resource. Earch resource 498must be enabled separately and each resource needs their own storage. 499 500.. code-block:: c 501 502 /* Allocate data cache storage */ 503 static struct lwm2m_time_series_elem temperature_cache[10]; 504 /* Enable data cache */ 505 lwm2m_engine_enable_cache(LWM2M_PATH(IPSO_OBJECT_TEMP_SENSOR_ID, 0, SENSOR_VALUE_RID), 506 temperature_cache, ARRAY_SIZE(temperature_cache)); 507 508LwM2M engine have room for four resources that have cache enabled. Limit can be increased by 509changing :kconfig:option:`CONFIG_LWM2M_MAX_CACHED_RESOURCES`. This affects a static memory usage of 510engine. 511 512Data caches depends on one of the SenML data formats 513:kconfig:option:`CONFIG_LWM2M_RW_SENML_CBOR_SUPPORT` or 514:kconfig:option:`CONFIG_LWM2M_RW_SENML_JSON_SUPPORT` and needs :kconfig:option:`CONFIG_POSIX_CLOCK` 515so it can request a timestamp from the system and :kconfig:option:`CONFIG_RING_BUFFER` for ring 516buffer. 517 518Read and Write operations 519========================= 520 521Full content of data cache is written into a payload when any READ, SEND or NOTIFY operation 522internally reads the content of a given resource. This has a side effect that any read callbacks 523registered for a that resource are ignored when cache is enabled. 524Data is written into a cache when any of the ``lwm2m_set_*`` functions are called. To filter 525the data entering the cache, application may register a validation callback using 526:c:func:`lwm2m_register_validate_callback`. 527 528Limitations 529=========== 530 531Cache size should be manually set so small that the content can fit normal packets sizes. 532When cache is full, new values are dropped. 533 534LwM2M engine and application events 535*********************************** 536 537The Zephyr LwM2M engine defines events that can be sent back to the application through callback 538functions. 539The engine state machine shows when the events are spawned. 540Events depicted in the diagram are listed in the table. 541The events are prefixed with ``LWM2M_RD_CLIENT_EVENT_``. 542 543.. figure:: images/lwm2m_engine_state_machine.png 544 :alt: LwM2M engine state machine 545 546 State machine for the LwM2M engine 547 548.. list-table:: LwM2M RD Client events 549 :widths: auto 550 :header-rows: 1 551 552 * - Event ID 553 - Event Name 554 - Description 555 - Actions 556 * - 0 557 - NONE 558 - No event 559 - Do nothing 560 * - 1 561 - BOOTSTRAP_REG_FAILURE 562 - Bootstrap registration failed. 563 Occurs if there is a timeout or failure in bootstrap registration. 564 - Retry bootstrap 565 * - 2 566 - BOOTSTRAP_REG_COMPLETE 567 - Bootstrap registration complete. 568 Occurs after successful bootstrap registration. 569 - No actions needed 570 * - 3 571 - BOOTSTRAP_TRANSFER_COMPLETE 572 - Bootstrap finish command received from the server. 573 - No actions needed, client proceeds to registration. 574 * - 4 575 - REGISTRATION_FAILURE 576 - Registration to LwM2M server failed. 577 Occurs if there is a failure in the registration. 578 - Retry registration 579 * - 5 580 - REGISTRATION_COMPLETE 581 - Registration to LwM2M server successful. 582 Occurs after a successful registration reply from the LwM2M server 583 or when session resumption is used. 584 - No actions needed 585 * - 6 586 - REG_TIMEOUT 587 - Registration or registration update timeout. 588 Occurs if there is a timeout during registration. 589 NOTE: If registration fails without a timeout, 590 a full registration is triggered automatically and 591 no registration update failure event is generated. 592 - No actions needed, client proceeds to re-registration automatically. 593 * - 7 594 - REG_UPDATE_COMPLETE 595 - Registration update completed. 596 Occurs after successful registration update reply from the LwM2M server. 597 - No actions needed 598 * - 8 599 - DEREGISTER_FAILURE 600 - Deregistration to LwM2M server failed. 601 Occurs if there is a timeout or failure in the deregistration. 602 - No actions needed, client proceeds to idle state automatically. 603 * - 9 604 - DISCONNECT 605 - Disconnected from LwM2M server. 606 Occurs if there is a timeout during communication with server. 607 Also triggered after deregistration has been done. 608 - If connection is required, the application should restart the client. 609 * - 10 610 - QUEUE_MODE_RX_OFF 611 - Used only in queue mode, not actively listening for incoming packets. 612 In queue mode the client is not required to actively listen for the incoming packets 613 after a configured time period. 614 - No actions needed 615 * - 11 616 - ENGINE_SUSPENDED 617 - Indicate that client has now paused as a result of calling :c:func:`lwm2m_engine_pause`. 618 State machine is no longer running and the handler thread is suspended. 619 All timers are stopped so notifications are not triggered. 620 - Engine can be resumed by calling :c:func:`lwm2m_engine_resume`. 621 * - 12 622 - NETWORK_ERROR 623 - Sending messages to the network failed too many times. 624 If sending a message fails, it will be retried. 625 If the retry counter reaches its limits, this event will be triggered. 626 - No actions needed, client will do a re-registrate automatically. 627 628.. _lwm2m_shell: 629 630LwM2M shell 631*********** 632For testing the client it is possible to enable Zephyr's shell and LwM2M specific commands which 633support changing the state of the client. Operations supported are read, write and execute 634resources. Client start, stop, pause and resume are also available. The feature is enabled by 635selecting :kconfig:option:`CONFIG_LWM2M_SHELL`. The shell is meant for testing so productions 636systems should not enable it. 637 638One imaginable scenario, where to use the shell, would be executing client side actions over UART 639when a server side tests would require those. It is assumed that not all tests are able to trigger 640required actions from the server side. 641 642.. code-block:: console 643 644 uart:~$ lwm2m 645 lwm2m - LwM2M commands 646 Subcommands: 647 send :send PATHS 648 LwM2M SEND operation 649 650 exec :exec PATH [PARAM] 651 Execute a resource 652 653 read :read PATH [OPTIONS] 654 Read value from LwM2M resource 655 -x Read value as hex stream (default) 656 -s Read value as string 657 -b Read value as bool (1/0) 658 -uX Read value as uintX_t 659 -sX Read value as intX_t 660 -f Read value as float 661 -t Read value as time_t 662 663 write :write PATH [OPTIONS] VALUE 664 Write into LwM2M resource 665 -s Write value as string (default) 666 -b Write value as bool 667 -uX Write value as uintX_t 668 -sX Write value as intX_t 669 -f Write value as float 670 -t Write value as time_t 671 672 create :create PATH 673 Create object instance 674 675 cache :cache PATH NUM 676 Enable data cache for resource 677 PATH is LwM2M path 678 NUM how many elements to cache 679 680 start :start EP_NAME [BOOTSTRAP FLAG] 681 Start the LwM2M RD (Registration / Discovery) Client 682 -b Set the bootstrap flag (default 0) 683 684 stop :stop [OPTIONS] 685 Stop the LwM2M RD (De-register) Client 686 -f Force close the connection 687 688 update :Trigger Registration Update of the LwM2M RD Client 689 690 pause :LwM2M engine thread pause 691 resume :LwM2M engine thread resume 692 lock :Lock the LwM2M registry 693 unlock :Unlock the LwM2M registry 694 695 696 697 698.. _lwm2m_api_reference: 699 700API Reference 701************* 702 703.. doxygengroup:: lwm2m_api 704 705.. _LwM2M: 706 https://www.omaspecworks.org/what-is-oma-specworks/iot/lightweight-m2m-lwm2m/ 707 708.. _LwM2M registry: 709 http://www.openmobilealliance.org/wp/OMNA/LwM2M/LwM2MRegistry.html 710 711.. _OMA Specworks LwM2M: 712 https://www.omaspecworks.org/what-is-oma-specworks/iot/lightweight-m2m-lwm2m/ 713 714.. _LwM2M specification 1.0.2: 715 http://openmobilealliance.org/release/LightweightM2M/V1_0_2-20180209-A/OMA-TS-LightweightM2M-V1_0_2-20180209-A.pdf 716 717.. _LwM2M specification 1.1.1: 718 http://openmobilealliance.org/release/LightweightM2M/V1_1_1-20190617-A/ 719