7.2. LwM2M Gateway API

7.2.1. LwM2M Gateway object

Before using the LwM2M Gateway object, we need to inform Anjay of its existence. Anjay includes a built-in implementation of the LwM2M Gateway object LwM2M Gateway (/25), which can be easily utilized.

Note

Anjay implements version 2.0 of Object /25 containing all three mandatory resources: Device ID, Prefix, and IoT Device Object.

Once the Anjay object is created, the Gateway object can be installed using the anjay_lwm2m_gateway_install() function.

Note

Complete code of this example can be found in examples/commercial-features/CF-LwM2M-Gateway subdirectory of the main Anjay project repository.

anjay_t *anjay = anjay_new(&CONFIG);
if (!anjay) {
    avs_log(tutorial, ERROR, "Could not create Anjay object");
    return -1;
}

int result = 0;
if (setup_security_object(anjay) || setup_server_object(anjay)) {
    result = -1;
}

if (!result && anjay_lwm2m_gateway_install(anjay)) {
    avs_log(tutorial, ERROR, "Failed to add /25 Gateway Object");
    result = -1;
}

7.2.2. Managing End Devices

Managing a new End Device involves two key steps:

  1. Establishing communication between the Gateway and the End Device.

  2. Registering the device and its objects in the LwM2M Gateway.

7.2.2.1. Communication with End Devices

Since different End Devices may have unique requirements, the communication method varies. The example provided in the next section includes a Python script examples/commercial-features/CF-LwM2M-Gateway/end_device.py. This script communicates with the Anjay example code using UNIX sockets. However, it is the user’s responsibility to implement the appropriate communication mechanism for their specific End Devices.

Note

The Python script can be started multiple times, and each instance of the script will automatically connect to the Gateway and simulate a single End Device. Stopping the execution of the script will dynamically disconnect the associated End Device from the LwM2M Gateway.

7.2.2.2. Registering an End Device

When a new End Device sends an attach request, the LwM2M Gateway must register it by adding a new instance of the /25 Gateway Object. This is done using the anjay_lwm2m_gateway_register_device() function.

static int setup_end_device(gateway_srv_t *gateway_srv,
                            end_device_t *end_device,
                            const char *msg) {
    anjay_iid_t iid = ANJAY_ID_INVALID;
    anjay_t *anjay = gateway_srv->anjay;

    strcpy(end_device->end_device_name, msg);
    if (anjay_lwm2m_gateway_register_device(anjay, end_device->end_device_name,
                                            &iid)) {
        avs_log(tutorial, ERROR, "Failed to add End Device");
        return -1;
    }
    end_device->iid = iid;
    end_device->evaluation_period = DEFAULT_MAXIMAL_EVALUATION_PERIOD;

7.2.2.3. Instance ID (iid) management

You can specify an Instance ID (iid) manually or set it to ANJAY_ID_INVALID to let Anjay assign the first available ID automatically. Always check the return code of anjay_lwm2m_gateway_register_device(), especially when assigning iid manually. If a collision occurs, the function will return a negative value without modifying the passed iid.

Important

The device_id parameter passed to anjay_lwm2m_gateway_register_device() must remain valid until the device is deregistered. The value is not copied internally.

7.2.2.4. Registering LwM2M objects for an End Device

Once an End Device is registered, its supported LwM2M objects must also be registered. In the provided example, only one object: Temperature Object (/3303) (LwM2M Temperature Object Specification) is registered.

To register an object, use the anjay_lwm2m_gateway_register_object() function. The object implementation should handle communication with the End Device, but otherwise follows the same pattern as anjay_register_object().

const anjay_dm_object_def_t **obj =
        temperature_object_create(iid, gateway_srv);
if (!obj) {
    avs_log(tutorial, ERROR, "Failed to create Temperature Object");
    return -1;
}
end_device->temperature_object = obj;

if (anjay_lwm2m_gateway_register_object(anjay, iid, obj)) {
    avs_log(tutorial, ERROR, "Failed to register Temperature Object");
    return -1;
}

Note

The Temperature Object implementation (examples/tutorial/LwM2M-Gateway/src/temperature_object.c) interacts with the Python script simulating an End Device to perform actual read and write operations.

Note

The Anjay LwM2M Gateway automatically assigns Prefixes (/25/*/1). However, when using the LwM2M Gateway API, users should rely on the integer End Device Instance ID returned by anjay_lwm2m_gateway_register_device(). It is recommended to store the Instance ID in a structure representing the object registered on the End Device. This makes it easier to match the correct End Device when using shared object implementations.

7.2.3. Cleaning up

When a device disconnects, the user should perform two actions:

  • Unregister all of the objects of a given End Device using anjay_lwm2m_gateway_unregister_object()

  • Deregister the End Device with anjay_lwm2m_gateway_deregister_device()

if (end_device->temperature_object) {
    if (anjay_lwm2m_gateway_unregister_object(
                anjay, end_device->iid, end_device->temperature_object)) {
        avs_log(tutorial, ERROR, "Failed to unregister Temperature Object");
    }
    temperature_object_release(end_device->temperature_object);
}
if (anjay_lwm2m_gateway_deregister_device(anjay, end_device->iid)) {
    avs_log(tutorial, ERROR, "Failed to deregister End Device");
}