LwM2M Client does not respect observer attributes

Hi everyone

We have had the experience on two different LwM2M servers that the Observer attributes are not being respected by the LwM2M client. Reading the Observer attributes we can also see that they are set, but just not respected

pmin:

- Minimum time between updates

- even if the observed value changes, the Observer will not send an update before pmin seconds --> e.g. A changing value will only be updated every 10 minutes, even if it changes every 30 seconds

- Works as intended

pmax:

- Maximum time between updates

- even if the observed value doesn't change, the Observer will send an update after pmax seconds --> e.g. At least one value every 6h, even if it does not change

- works as intended

gt:

- Threshold value

- Observer only sends an update if the observed value EXCEEDS a certain threshold --> e.g. Temperatures under 25°C are ignored. An update is only sent when Value crosses Threshold or after pmax has expired

- does not work as expected

lt:

- Threshold value

- Same as above, but reversed. Only reports values BELOW the threshold --> e.g. Temperatures above 36°C are ignored

- does not work as expected

st:

- Step value

- Observer reports the value if it changes by X from one measurement to the other --> e.g. Change from 36.2°C to 36.4°C is ignored, but a change from 36.2°C to 22.3°C is reported

- does not work as expected

Does anyone have any experience with this issue?

We are working on a custom Board based on the Thingy:91; running Toolchain v2.6.2, modem Firmware v1.3.6, Application based on the LwM2M Client Sample.

This Issue should be reproducible on a Thingy:91 running the LwM2M Client sample though.

I will update this post with more information tomorrow

Parents
  • Thanks for reporting this issue.

    Not sure which NCS version are you based on? Looks this is related to Zephyr lwm2m client library which has source codes located in ncs/zephyr/subsys/net/lib/lwm2m/lwm2m_observation.c.

    I will give it a try tomorrow.

    Best regards,

    Charlie

  • Hi Charlie

    Thanks for your answer.

    Have you been able to reproduce the issue?

    I'm starting to suspect that we messed up something somewhere while making our custom application. Since we only ever tested pmin and pmax, I guess somewhere the other 3 observer attributes broke, but I'm not sure. Is there something you have to specifically set so the attributes are set? I assumed that if pmin and pmax work, the rest should work as well.

    Thanks for any pointers on where to look.

    Best regards,

    Alan

  • Hi,

    I checked our official sample NCS 2.7.0 Cellular: LwM2M Client (nordicsemi.com) with Coiote LwM2M server, looks all the observer attributes work as expected.

    Here is one example for Push button Digital Input Counter: pimin=10, pmax=20, st=2.

    Observe the change in a widget:

    When I do not push the button, the update interval is 20s. When I push the button two times to increase the counter from 1 to 3, the update triggered in 10s.

    Please have a try with your setup. 

    Best regards,

    Charlie

  • Hi Charlie,

    Thanks for taking the time to try to reproduce the bug. We started working with NCS 2.4.2, then ported the application to NCS 2.6.0, which we are currently working with. Do you recommend updating to NCS 2.7.0?

    We are now troubleshooting with different servers with the base LwM2M Client sample and our custom application and will keep you updated on our findings.

    General question: Which steps are necessary for adding a new, fully functional LwM2M object?

    Is it more than just creating the object? example for device object

    Path: C:\ncs\v2.6.0\zephyr\subsys\net\lib\lwm2m\lwm2m_obj_device.c:

    static struct lwm2m_engine_obj_inst *device_create(uint16_t obj_inst_id)
    {
                    int i = 0, j = 0;
    
                    init_res_instance(res_inst, ARRAY_SIZE(res_inst));
    
                    /* initialize instance resource data */
                    INIT_OBJ_RES_OPTDATA(DEVICE_MANUFACTURER_ID, res, i, res_inst, j);
                    INIT_OBJ_RES_OPTDATA(DEVICE_MODEL_NUMBER_ID, res, i, res_inst, j);
                    INIT_OBJ_RES_OPTDATA(DEVICE_SERIAL_NUMBER_ID, res, i, res_inst, j);
                    INIT_OBJ_RES_OPTDATA(DEVICE_FIRMWARE_VERSION_ID, res, i, res_inst, j);
                    INIT_OBJ_RES_EXECUTE(DEVICE_REBOOT_ID, res, i, NULL);
                    INIT_OBJ_RES_EXECUTE(DEVICE_FACTORY_DEFAULT_ID, res, i, NULL);
                    INIT_OBJ_RES_MULTI_OPTDATA(DEVICE_AVAILABLE_POWER_SOURCES_ID, res, i,
                                                                      res_inst, j, DEVICE_PWRSRC_MAX, false);
                    INIT_OBJ_RES_MULTI_OPTDATA(DEVICE_POWER_SOURCE_VOLTAGE_ID, res, i,
                                                                      res_inst, j, DEVICE_PWRSRC_MAX, false);
                    INIT_OBJ_RES_MULTI_OPTDATA(DEVICE_POWER_SOURCE_CURRENT_ID, res, i,
                                                                      res_inst, j, DEVICE_PWRSRC_MAX, false);
                    INIT_OBJ_RES_OPTDATA(DEVICE_BATTERY_LEVEL_ID, res, i, res_inst, j);
                    INIT_OBJ_RES_OPTDATA(DEVICE_MEMORY_FREE_ID, res, i, res_inst, j);
                    error_code_ri = &res_inst[j];
                    INIT_OBJ_RES_MULTI_DATA(DEVICE_ERROR_CODE_ID, res, i,
                                                                   res_inst, j, DEVICE_ERROR_CODE_MAX, false,
                                                                   error_code_list, sizeof(*error_code_list));
                    INIT_OBJ_RES_EXECUTE(DEVICE_RESET_ERROR_CODE_ID, res, i,
                                                        reset_error_list_cb);
                    INIT_OBJ_RES_OPT(DEVICE_CURRENT_TIME_ID, res, i, res_inst, j, 1, false,
                                                   true, current_time_read_cb, current_time_pre_write_cb,
                                                   NULL, current_time_post_write_cb, NULL);
                    INIT_OBJ_RES_OPTDATA(DEVICE_UTC_OFFSET_ID, res, i, res_inst, j);
                    INIT_OBJ_RES_OPTDATA(DEVICE_TIMEZONE_ID, res, i, res_inst, j);
                    INIT_OBJ_RES_DATA(DEVICE_SUPPORTED_BINDING_MODES_ID, res, i,
                                                     res_inst, j, binding_mode, DEVICE_STRING_SHORT);
                    INIT_OBJ_RES_OPTDATA(DEVICE_TYPE_ID, res, i, res_inst, j);
                    INIT_OBJ_RES_OPTDATA(DEVICE_HARDWARE_VERSION_ID, res, i, res_inst, j);
                    INIT_OBJ_RES_OPTDATA(DEVICE_SOFTWARE_VERSION_ID, res, i, res_inst, j);
                    INIT_OBJ_RES_OPTDATA(DEVICE_BATTERY_STATUS_ID, res, i, res_inst, j);
                    INIT_OBJ_RES_OPTDATA(DEVICE_MEMORY_TOTAL_ID, res, i, res_inst, j);
                    INIT_OBJ_RES_MULTI_OPTDATA(DEVICE_EXT_DEV_INFO_ID, res, i, res_inst, j,
                                                                      DEVICE_EXT_DEV_INFO_MAX, false);
    
                    inst.resources = res;
                    inst.resource_count = i;
    
                    LOG_DBG("Create LWM2M device instance: %d", obj_inst_id);
                    return &inst;
    }
    
    static int lwm2m_device_init(void)
    {
                    struct lwm2m_engine_obj_inst *obj_inst = NULL;
                    int ret = 0;
    
                    /* Set default values */
                    time_offset = 0U;
                    lwm2m_engine_get_binding(binding_mode);
    
                    /* initialize the device field data */
                    device.obj_id = LWM2M_OBJECT_DEVICE_ID;
                    device.version_major = DEVICE_VERSION_MAJOR;
                    device.version_minor = DEVICE_VERSION_MINOR;
                    device.is_core = true;
                    device.fields = fields;
                    device.field_count = ARRAY_SIZE(fields);
                    device.max_instance_count = 1U;
                    device.create_cb = device_create;
                    lwm2m_register_obj(&device);
    
                    /* auto create the only instance */
                    ret = lwm2m_create_obj_inst(LWM2M_OBJECT_DEVICE_ID, 0, &obj_inst);
                    if (ret < 0) {
                                   LOG_DBG("Create LWM2M instance 0 error: %d", ret);
                    }
    
                    /* Create the default error code resource instance */
                    lwm2m_device_add_err(0);
    
                    /* call device_periodic_service() every 10 seconds */
                    ret = lwm2m_engine_add_service(device_periodic_service,
                                                                          DEVICE_SERVICE_INTERVAL_MS);
                    return ret;
    }
    

    Because that's what we did for all our objects and everything else works. We shouldn't have to initialise these observer attributes in a special way, or should we?

  • Hi Charlie

    Ah, now I see where the confusion about the toolchain came from. I misstyped v2.6.0 before, sorry!

    I didn't use the button, but instead manipulated the application so that it's closer to our product case.

    But I just managed to reproduce the issue using the base NCS 2.6.0 LwM2M client sample.

    My steps were:

    1. Start with the NCS 2.6.0 LwM2M client sample

    2. Add the 3 lwm2m 1.1 overlays (core-interop, object-interop & 1.1.conf)

    3. Add debugging and other essential Configs:

    CONFIG_APP_LWM2M_PSK="000102030405060708090a0b0c0d0e0e"
    
    CONFIG_LWM2M_CLIENT_UTILS_SERVER="coaps://eu.iot.avsystem.cloud"
    
    CONFIG_LWM2M_PEER_PORT=5684
    
    CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP=n
    
    CONFIG_APP_ENDPOINT_PREFIX="ugn:imei:"
    
    CONFIG_LWM2M_DTLS_SUPPORT=y
    
      
    
    
    CONFIG_LWM2M_DTLS_CID=y
    
    CONFIG_LWM2M_CLIENT_UTILS_DTLS_CON_MANAGEMENT=n
    
    CONFIG_LTE_LC_MODEM_SLEEP_NOTIFICATIONS=y
    
    CONFIG_LWM2M_RD_CLIENT_LISTEN_AT_IDLE=n
    
    
    CONFIG_LWM2M_UPDATE_PERIOD=90
    
    CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME=43260
    
    CONFIG_LWM2M_SECONDS_TO_UPDATE_EARLY=60
    
      
    
    CONFIG_LWM2M_LOG_LEVEL_DBG=y
    
      
    
    CONFIG_THREAD_MONITOR=n
    
    CONFIG_USE_SEGGER_RTT=y
    
    CONFIG_STDOUT_CONSOLE=y
    
    CONFIG_SERIAL=y
    
    CONFIG_LOG=y
    
    CONFIG_THREAD_NAME=n
    
    CONFIG_NRF_MODEM_LIB_TRACE=n
    
    CONFIG_SENSOR_MODULE=y

    (4.) We add a devicetree overlay to make the application work on our hardware; should not influence the application:

    &pinctrl {
    	uart0_default: uart0_default {
    		group1 {
    			psels = <NRF_PSEL(UART_TX, 0, 22)>,
    				<NRF_PSEL(UART_RTS, 0, 24)>;
    		};
    		group2 {
    			psels = <NRF_PSEL(UART_RX, 0, 23)>,
    				<NRF_PSEL(UART_CTS, 0, 25)>;
    			bias-pull-up;
    		};
    	};
    
    	uart0_sleep: uart0_sleep {
    		group1 {
    			psels = <NRF_PSEL(UART_TX, 0, 22)>,
    				<NRF_PSEL(UART_RX, 0, 23)>,
    				<NRF_PSEL(UART_RTS, 0, 24)>,
    				<NRF_PSEL(UART_CTS, 0, 25)>;
    			low-power-enable;
    		};
    	};
    };
    
    &i2c2 {
    	sht40_platine: sht4x@45 {
    		compatible = "sensirion,sht4x";
    		reg = <0x45>;
    		repeatability = < 2 >;
    	};
    };
    
    &uart0 {
    	status = "okay";
    	current-speed = <115200>;
    	pinctrl-0 = <&uart0_default>;
    	pinctrl-1 = <&uart0_sleep>;
    	pinctrl-names = "default", "sleep";
    };
    
    &spi3 {
    	status = "disabled";
    };
    
    &adxl362 {
    	status = "disabled";
    };
    
    &adxl372 {
    	status = "disabled";
    };
    
    &sense_blue_led {
    	status = "disabled";
    };
    
    &sense_red_led {
    	status = "disabled";
    };
    
    &sense_green_led {
    	status = "disabled";
    };
    
    &nrf52840_reset {
    	status = "disabled";
    };
    
    &bh1749 {
    	status = "disabled";
    };
    
    &bme680 {
    	status = "disabled";
    };
    
    &pwm0 {
    	status = "disabled";
    };
    
    &pwm1 {
    	status = "disabled";
    };
    
    &pwm2 {
    	status = "disabled";
    };
    
    &gpiote {
    	status = "okay";
    };
    
    
    &gpio0 {
    	sense-edge-mask = < (1ULL << 26) >;
    };
    
    &i2c2 {
        ads1015: ads1015@48 {
            compatible = "ti,ads1015";
            #io-channel-cells = <1>;
            reg = < 0x48 >;
        };
    
    	sht40_rechen: sht4x@44 {
    		compatible = "sensirion,sht4x";
    		reg = <0x44>;
    		repeatability = < 2 >;
    	};
    };

    5. Modify sensor module to write a simulated battery percentage to the resource /3/0/9 every 10 seconds:

    Change

    #define PERIOD K_MINUTES(2)

    to

    #define PERIOD K_SECONDS(10)

    And modify pmic_work_cb to the following:

    static void pmic_work_cb(struct k_work *work)
    {
    	int rc;
    	uint8_t percentage;
    	uint16_t millivolts;
    	uint8_t status;
    
    
    	rc = adp536x_fg_soc(&percentage);
    	if (rc) {
    		k_work_schedule(&pmic_work, RETRY);
    		return;
    	}
    
    	rc = adp536x_fg_volts(&millivolts);
    	if (rc) {
    		k_work_schedule(&pmic_work, RETRY);
    		return;
    	}
    
    	rc = adp536x_charger_status_1_read(&status);
    	if (rc) {
    		k_work_schedule(&pmic_work, RETRY);
    		return;
    	}
    
    	uint8_t rand_0_to_255 = rand();
    	uint8_t sim_percentage;
    
    	sim_percentage = floor(rand_0_to_255/2.55);
    
    	printk("\ngenerated simulated battery percentage: %i percent\n", sim_percentage);
    
    	lwm2m_set_u8(&LWM2M_OBJ(3, 0, 9), sim_percentage);
    
    	lwm2m_set_s32(&LWM2M_OBJ(3, 0, 7, 0), (int) millivolts);
    
    	k_work_schedule(&pmic_work, PERIOD);
    }
    

    6. Flash application to device

    7. Register to Coiote server and set observer with attributes

    8. Observe the logs and see that the device ignores the step attribute:

    [00:00:10.575,225] <dbg> net_lwm2m_rd_client: sm_send_registration: registration sent [35.204.45.127]
    [00:00:10.576,660] <dbg> net_lwm2m_rd_client: lwm2m_rd_client_service: State: 8
    [00:00:10.716,094] <dbg> net_lwm2m_rd_client: do_registration_reply_cb: Registration callback (code:2.1)
    [00:00:10.716,827] <dbg> net_lwm2m_registry: lwm2m_engine_get: path:1/0/1/0, level 3, buf:0x2001f1d0, buflen:4
    [00:00:10.717,468] <dbg> app_lwm2m_client: rd_client_event: Registration complete
    [00:00:10.717,590] <inf> net_lwm2m_rd_client: Registration Done (EP='ugn:imei:350457793178730')
    [00:00:10.717,742] <dbg> net_lwm2m_message_handling: lwm2m_udp_receive: reply 0x2000d1e8 handled and removed
    [00:00:10.717,834] <dbg> net_lwm2m_rd_client: lwm2m_rd_client_service: State: 9
    [00:00:10.718,475] <inf> app_lwm2m_client: LwM2M is connected to server
    [00:00:10.718,475] <dbg> net_lwm2m_registry: lwm2m_engine_get: path:1/0/1/0, level 3, buf:0x20021438, buflen:4
    [00:00:10.723,632] <inf> app_lwm2m_client: Obtained date-time from modem
    [00:00:10.723,663] <dbg> net_lwm2m_registry: lwm2m_engine_set: path:3/0/13, buf:0x2001fadc, len:4
    [00:00:10.733,123] <dbg> net_lwm2m_message_handling: lwm2m_engine_default_content_format: No accept option given. Assume SenML CBOR.
    [00:00:10.870,483] <dbg> net_lwm2m_message_handling: lwm2m_engine_default_content_format: No accept option given. Assume SenML CBOR.
    [00:00:10.870,605] <dbg> net_lwm2m_observation: lwm2m_write_attr_handler: Add pmin to 10
    [00:00:10.870,635] <dbg> net_lwm2m_observation: lwm2m_write_attr_handler: Add pmax to 75
    [00:00:10.870,697] <dbg> net_lwm2m_observation: lwm2m_write_attr_handler: Add st to 50.000000
    [00:00:10.943,450] <dbg> net_lwm2m_message_handling: lwm2m_engine_default_content_format: No accept option given. Assume SenML CBOR.
    [00:00:10.943,542] <dbg> net_lwm2m_observation: engine_observe_node_init: OBSERVER ADDED 3/0/9/0(3)
    [00:00:10.943,603] <dbg> net_lwm2m_observation: engine_observe_node_init: token:'fb00f55f1ca13060' addr:35.204.45.127
    [00:00:13.741,912] <dbg> net_lwm2m_message_handling: lwm2m_engine_default_content_format: No accept option given. Assume SenML CBOR.
    [00:00:13.847,900] <dbg> net_lwm2m_message_handling: lwm2m_engine_default_content_format: No accept option given. Assume SenML CBOR.
    [00:00:14.030,944] <dbg> net_lwm2m_message_handling: lwm2m_engine_default_content_format: No accept option given. Assume SenML CBOR.
    
    generated simulated battery percentage: 81 percent
    [00:00:14.146,759] <dbg> net_lwm2m_registry: lwm2m_engine_set: path:3/0/9, buf:0x20025c07, len:1
    [00:00:14.146,820] <dbg> net_lwm2m_observation: lwm2m_notify_observer_path: NOTIFY EVENT 3/0/9
    [00:00:14.146,911] <dbg> net_lwm2m_registry: lwm2m_engine_set: path:3/0/7, buf:0x20025c04, len:4
    [00:00:14.176,940] <dbg> net_lwm2m_message_handling: lwm2m_engine_default_content_format: No accept option given. Assume SenML CBOR.
    [00:00:14.303,955] <dbg> net_lwm2m_message_handling: lwm2m_engine_default_content_format: No accept option given. Assume SenML CBOR.
    [00:00:20.943,847] <dbg> net_lwm2m_message_handling: generate_notify_message: [MANUAL] NOTIFY MSG START: 3/0/9(3) token:'fb00f55f1ca13060' [35.204.45.127] 20943
    [00:00:20.944,946] <dbg> net_lwm2m_message_handling: generate_notify_message: NOTIFY MSG: SENT
    [00:00:21.099,212] <dbg> net_lwm2m_message_handling: notify_message_reply_cb: NOTIFY ACK type:2 code:0.0 reply_token:'fb00f55f1ca13060'
    [00:00:21.099,365] <dbg> net_lwm2m_message_handling: lwm2m_udp_receive: reply 0x2000d1e8 handled and removed
    
    generated simulated battery percentage: 27 percent
    [00:00:24.148,468] <dbg> net_lwm2m_registry: lwm2m_engine_set: path:3/0/9, buf:0x20025c07, len:1
    [00:00:24.148,559] <dbg> net_lwm2m_observation: lwm2m_notify_observer_path: NOTIFY EVENT 3/0/9
    [00:00:24.148,651] <dbg> net_lwm2m_registry: lwm2m_engine_set: path:3/0/7, buf:0x20025c04, len:4
    [00:00:30.944,122] <dbg> net_lwm2m_message_handling: generate_notify_message: [MANUAL] NOTIFY MSG START: 3/0/9(3) token:'fb00f55f1ca13060' [35.204.45.127] 30944
    [00:00:30.945,220] <dbg> net_lwm2m_message_handling: generate_notify_message: NOTIFY MSG: SENT
    [00:00:31.105,529] <dbg> net_lwm2m_message_handling: notify_message_reply_cb: NOTIFY ACK type:2 code:0.0 reply_token:'fb00f55f1ca13060'
    [00:00:31.105,712] <dbg> net_lwm2m_message_handling: lwm2m_udp_receive: reply 0x2000d1e8 handled and removed
    
    generated simulated battery percentage: 16 percent
    [00:00:34.150,177] <dbg> net_lwm2m_registry: lwm2m_engine_set: path:3/0/9, buf:0x20025c07, len:1
    [00:00:34.150,268] <dbg> net_lwm2m_observation: lwm2m_notify_observer_path: NOTIFY EVENT 3/0/9
    [00:00:34.150,360] <dbg> net_lwm2m_registry: lwm2m_engine_set: path:3/0/7, buf:0x20025c04, len:4
    [00:00:40.576,751] <dbg> net_lwm2m_rd_client: lwm2m_rd_client_service: State: 9
    [00:00:40.944,366] <dbg> net_lwm2m_message_handling: generate_notify_message: [MANUAL] NOTIFY MSG START: 3/0/9(3) token:'fb00f55f1ca13060' [35.204.45.127] 40944
    [00:00:40.945,434] <dbg> net_lwm2m_message_handling: generate_notify_message: NOTIFY MSG: SENT
    [00:00:41.089,904] <dbg> net_lwm2m_message_handling: notify_message_reply_cb: NOTIFY ACK type:2 code:0.0 reply_token:'fb00f55f1ca13060'
    [00:00:41.090,057] <dbg> net_lwm2m_message_handling: lwm2m_udp_receive: reply 0x2000d1e8 handled and removed
    
    generated simulated battery percentage: 1 percent
    [00:00:44.151,885] <dbg> net_lwm2m_registry: lwm2m_engine_set: path:3/0/9, buf:0x20025c07, len:1
    [00:00:44.151,977] <dbg> net_lwm2m_observation: lwm2m_notify_observer_path: NOTIFY EVENT 3/0/9
    [00:00:44.152,069] <dbg> net_lwm2m_registry: lwm2m_engine_set: path:3/0/7, buf:0x20025c04, len:4
    [00:00:50.944,549] <dbg> net_lwm2m_message_handling: generate_notify_message: [MANUAL] NOTIFY MSG START: 3/0/9(3) token:'fb00f55f1ca13060' [35.204.45.127] 50944
    [00:00:50.945,648] <dbg> net_lwm2m_message_handling: generate_notify_message: NOTIFY MSG: SENT
    [00:00:51.009,246] <dbg> net_lwm2m_message_handling: notify_message_reply_cb: NOTIFY ACK type:2 code:0.0 reply_token:'fb00f55f1ca13060'
    [00:00:51.009,399] <dbg> net_lwm2m_message_handling: lwm2m_udp_receive: reply 0x2000d1e8 handled and removed
    
    generated simulated battery percentage: 70 percent
    [00:00:54.153,594] <dbg> net_lwm2m_registry: lwm2m_engine_set: path:3/0/9, buf:0x20025c07, len:1
    [00:00:54.153,686] <dbg> net_lwm2m_observation: lwm2m_notify_observer_path: NOTIFY EVENT 3/0/9
    [00:00:54.153,778] <dbg> net_lwm2m_registry: lwm2m_engine_set: path:3/0/7, buf:0x20025c04, len:4
    [00:01:00.945,251] <dbg> net_lwm2m_message_handling: generate_notify_message: [MANUAL] NOTIFY MSG START: 3/0/9(3) token:'fb00f55f1ca13060' [35.204.45.127] 60945
    [00:01:00.946,350] <dbg> net_lwm2m_message_handling: generate_notify_message: NOTIFY MSG: SENT
    [00:01:00.955,566] <dbg> net_lwm2m_rd_client: lwm2m_rd_client_service: State: 9
    [00:01:01.096,588] <dbg> net_lwm2m_message_handling: notify_message_reply_cb: NOTIFY ACK type:2 code:0.0 reply_token:'fb00f55f1ca13060'
    [00:01:01.096,771] <dbg> net_lwm2m_message_handling: lwm2m_udp_receive: reply 0x2000d1e8 handled and removed
    
    generated simulated battery percentage: 47 percent
    [00:01:04.155,303] <dbg> net_lwm2m_registry: lwm2m_engine_set: path:3/0/9, buf:0x20025c07, len:1
    [00:01:04.155,395] <dbg> net_lwm2m_observation: lwm2m_notify_observer_path: NOTIFY EVENT 3/0/9
    [00:01:04.155,487] <dbg> net_lwm2m_registry: lwm2m_engine_set: path:3/0/7, buf:0x20025c04, len:4
    [00:01:10.945,953] <dbg> net_lwm2m_message_handling: generate_notify_message: [MANUAL] NOTIFY MSG START: 3/0/9(3) token:'fb00f55f1ca13060' [35.204.45.127] 70945
    [00:01:10.947,052] <dbg> net_lwm2m_message_handling: generate_notify_message: NOTIFY MSG: SENT
    [00:01:11.173,767] <dbg> net_lwm2m_message_handling: notify_message_reply_cb: NOTIFY ACK type:2 code:0.0 reply_token:'fb00f55f1ca13060'
    [00:01:11.173,950] <dbg> net_lwm2m_message_handling: lwm2m_udp_receive: reply 0x2000d1e8 handled and removed
    
    generated simulated battery percentage: 84 percent
    [00:01:14.157,012] <dbg> net_lwm2m_registry: lwm2m_engine_set: path:3/0/9, buf:0x20025c07, len:1
    [00:01:14.157,104] <dbg> net_lwm2m_observation: lwm2m_notify_observer_path: NOTIFY EVENT 3/0/9
    [00:01:14.157,196] <dbg> net_lwm2m_registry: lwm2m_engine_set: path:3/0/7, buf:0x20025c04, len:4
    [00:01:16.191,894] <dbg> net_lwm2m_registry: lwm2m_engine_set: path:4/0/2, buf:0x20025c16, len:2
    [00:01:20.945,678] <dbg> net_lwm2m_message_handling: generate_notify_message: [MANUAL] NOTIFY MSG START: 3/0/9(3) token:'fb00f55f1ca13060' [35.204.45.127] 80945
    [00:01:20.946,777] <dbg> net_lwm2m_message_handling: generate_notify_message: NOTIFY MSG: SENT
    [00:01:21.102,264] <dbg> net_lwm2m_message_handling: notify_message_reply_cb: NOTIFY ACK type:2 code:0.0 reply_token:'fb00f55f1ca13060'
    [00:01:21.102,447] <dbg> net_lwm2m_message_handling: lwm2m_udp_receive: reply 0x2000d1e8 handled and removed

    Same with gt and lt.

    Do you see any issues with the configuration or is it something else?

    Thanks for looking at this problem.

    Since it worked for you, I will try to reproduce the same with NCS 2.7.0 now.

    Best regards,

    Alan

  • Here you see the same information as in the Logs in the message above:

    With a Step of 50

    It sends every 10 seconds, even if the step is < 50

Reply Children
  • I just replicated this on ncs v2.7.0 with the same behaviour:

    I had to modify the sensor module a little to get the application to build:

    /*
     * Copyright (c) 2021 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
     
    #include <zephyr/kernel.h>
    #include <zephyr/drivers/sensor.h>
    #include <zephyr/net/lwm2m.h>
    #include <lwm2m_resource_ids.h>
    #include <math.h>
    #include <stdlib.h>
    #include <adp536x.h>
    #include "lwm2m_app_utils.h"
    #include "lwm2m_engine.h"
    #include "accelerometer.h"
    #include "env_sensor.h"
    #include "light_sensor.h"
     
    #include <zephyr/logging/log.h>
    LOG_MODULE_REGISTER(app_sensors, CONFIG_APP_LOG_LEVEL);
     
    #define LIGHT_OBJ_INSTANCE_ID 0
    #define COLOUR_OBJ_INSTANCE_ID 1
     
    static struct k_work_delayable accel_work;
    static struct k_work_delayable temp_work;
    static struct k_work_delayable press_work;
    static struct k_work_delayable humid_work;
    static struct k_work_delayable gas_res_work;
    static struct k_work_delayable light_work;
    static struct k_work_delayable colour_work;
    static struct k_work_delayable pmic_work;
     
    #define PERIOD K_SECONDS(10)
    #define RETRY K_MSEC(200)
     
    static void accel_work_cb(struct k_work *work)
    {
        double x;
        double y;
        double z;
        struct accelerometer_sensor_data data;
     
        accelerometer_read(&data);
        x = sensor_value_to_double(&data.x);
        y = sensor_value_to_double(&data.y);
        z = sensor_value_to_double(&data.z);
     
        lwm2m_set_f64(&LWM2M_OBJ(IPSO_OBJECT_ACCELEROMETER_ID, 0, X_VALUE_RID), x);
        lwm2m_set_f64(&LWM2M_OBJ(IPSO_OBJECT_ACCELEROMETER_ID, 0, Y_VALUE_RID), y);
        lwm2m_set_f64(&LWM2M_OBJ(IPSO_OBJECT_ACCELEROMETER_ID, 0, Z_VALUE_RID), z);
     
        k_work_schedule(&accel_work, PERIOD);
    }
     
    static void sensor_worker(int (*read_cb)(struct sensor_value *), const struct lwm2m_obj_path *path)
    {
        double val;
        struct sensor_value data;
        int rc;
     
        rc = read_cb(&data);
        if (rc) {
            LOG_ERR("Failed to read sensor data");
            return;
        }
        val = sensor_value_to_double(&data);
     
        lwm2m_set_f64(path, val);
    }
     
    static void temp_work_cb(struct k_work *work)
    {
        sensor_worker(env_sensor_read_temperature,
                  &LWM2M_OBJ(IPSO_OBJECT_TEMP_SENSOR_ID, 0, SENSOR_VALUE_RID));
     
        k_work_schedule(&temp_work, PERIOD);
    }
     
    static void press_work_cb(struct k_work *work)
    {
        sensor_worker(env_sensor_read_pressure,
                  &LWM2M_OBJ(IPSO_OBJECT_PRESSURE_ID, 0, SENSOR_VALUE_RID));
     
        k_work_schedule(&press_work, PERIOD);
    }
     
    static void humid_work_cb(struct k_work *work)
    {
        sensor_worker(env_sensor_read_humidity,
                  &LWM2M_OBJ(IPSO_OBJECT_HUMIDITY_SENSOR_ID, 0, SENSOR_VALUE_RID));
     
        k_work_schedule(&humid_work, PERIOD);
    }
     
    static void gas_res_work_cb(struct k_work *work)
    {
        sensor_worker(env_sensor_read_gas_resistance,
                  &LWM2M_OBJ(IPSO_OBJECT_GENERIC_SENSOR_ID, 0, SENSOR_VALUE_RID));
     
        k_work_schedule(&gas_res_work, PERIOD);
    }
     
    static int light_sensor_worker(int (*read_cb)(uint32_t *), const struct lwm2m_obj_path *path)
    {
        uint32_t val;
        int ret;
        char temp[RGBIR_STR_LENGTH];
     
        /* Read sensor, try again later if busy */
        if (read_cb(&val) == -EBUSY) {
            return -1;
        }
     
        ret = snprintk(temp, RGBIR_STR_LENGTH, "0x%08X", val);
        if (ret <= 0) {
            return -ENOMEM;
        }
        ret = lwm2m_set_string(path, temp);
        if (ret) {
            return ret;
        }
     
        return 0;
    }
     
    static void light_work_cb(struct k_work *work)
    {
        int rc = light_sensor_worker(light_sensor_read,
                         &LWM2M_OBJ(IPSO_OBJECT_COLOUR_ID, LIGHT_OBJ_INSTANCE_ID,
                            COLOUR_RID));
     
        if (rc) {
            k_work_schedule(&light_work, RETRY);
            return;
        }
     
        k_work_schedule(&light_work, PERIOD);
    }
     
    static void colour_work_cb(struct k_work *work)
    {
        int rc = light_sensor_worker(colour_sensor_read,
                         &LWM2M_OBJ(IPSO_OBJECT_COLOUR_ID, COLOUR_OBJ_INSTANCE_ID,
                            COLOUR_RID));
     
        if (rc) {
            k_work_schedule(&light_work, RETRY);
            return;
        }
     
        k_work_schedule(&colour_work, PERIOD);
    }
     
    static void pmic_work_cb(struct k_work *work)
    {
     
        uint8_t rand_0_to_255 = rand();
        uint8_t sim_percentage;
     
        sim_percentage = floor(rand_0_to_255/2.55);
     
        printk("\ngenerated simulated battery percentage: %i percent\n", sim_percentage);
     
        lwm2m_set_u8(&LWM2M_OBJ(3, 0, 9), sim_percentage);
     
        k_work_schedule(&pmic_work, PERIOD);
    }
     
    static int sensor_module_init(void)
    {
        if (IS_ENABLED(CONFIG_SENSOR_MODULE_ACCEL)) {
            k_work_init_delayable(&accel_work, accel_work_cb);
            k_work_schedule(&accel_work, K_NO_WAIT);
        }
     
        if (IS_ENABLED(CONFIG_SENSOR_MODULE_TEMP)) {
            k_work_init_delayable(&temp_work, temp_work_cb);
            k_work_schedule(&temp_work, K_NO_WAIT);
        }
     
        if (IS_ENABLED(CONFIG_SENSOR_MODULE_PRESS)) {
            k_work_init_delayable(&press_work, press_work_cb);
            k_work_schedule(&press_work, K_NO_WAIT);
        }
     
        if (IS_ENABLED(CONFIG_SENSOR_MODULE_HUMID)) {
            k_work_init_delayable(&humid_work, humid_work_cb);
            k_work_schedule(&humid_work, K_NO_WAIT);
        }
     
        if (IS_ENABLED(CONFIG_SENSOR_MODULE_GAS_RES)) {
            k_work_init_delayable(&gas_res_work, gas_res_work_cb);
            k_work_schedule(&gas_res_work, K_NO_WAIT);
        }
     
        if (IS_ENABLED(CONFIG_SENSOR_MODULE_LIGHT)) {
            k_work_init_delayable(&light_work, light_work_cb);
            k_work_schedule(&light_work, K_NO_WAIT);
        }
     
        if (IS_ENABLED(CONFIG_SENSOR_MODULE_COLOUR)) {
            k_work_init_delayable(&colour_work, colour_work_cb);
            k_work_schedule(&colour_work, K_NO_WAIT);
        }
     
        k_work_init_delayable(&pmic_work, pmic_work_cb);
        k_work_schedule(&pmic_work, K_NO_WAIT);
     
        return 0;
    }
     
    LWM2M_APP_INIT(sensor_module_init);

    Everything else was identical to what I described 2 comments higher; same issue:

    What am I doing differently?

    Best Regards,

    Alan

Related