How to send readresponse on OnOff Output Cluster to Coordinator?

I am trying to send a OnOff output cluster information to Co-ordinator when a button is pressed in the nrf52840 DK.  The problem is the during the initial registration, the OnOff command is correctly sent, but after the button is pressed, I am unable to find the correct method to send the readresponse

Here is the complete program

#include <zephyr/types.h>
#include <zephyr.h>
#include <device.h>
#include <soc.h>
#include <drivers/pwm.h>
#include <logging/log.h>
#include <dk_buttons_and_leds.h>
#include <settings/settings.h>

#include <zboss_api.h>
#include <zboss_api_addons.h>
#include <zb_mem_config_med.h>
#include <zigbee/zigbee_app_utils.h>
#include <zigbee/zigbee_error_handler.h>
#include <zigbee/zigbee_zcl_scenes.h>
#include <zb_nrf_platform.h>

/* Switch endpoint */
#define HA_SWITCH_ENDPOINT      12

/* Version of the application software (1 byte). */
#define SWITCH_INIT_BASIC_APP_VERSION     01

/* Version of the implementation of the Zigbee stack (1 byte). */
#define SWITCH_INIT_BASIC_STACK_VERSION   10

/* Version of the hardware of the device (1 byte). */
#define SWITCH_INIT_BASIC_HW_VERSION      11

/* Manufacturer name (32 bytes). */
#define SWITCH_INIT_BASIC_MANUF_NAME      "DongleNordic"

/* Model number assigned by manufacturer (32-bytes long string). */
#define SWITCH_INIT_BASIC_MODEL_ID        "DongleSwitch"

/* First 8 bytes specify the date of manufacturer of the device
 * in ISO 8601 format (YYYYMMDD). The rest (8 bytes) are manufacturer specific.
 */
#define SWITCH_INIT_BASIC_DATE_CODE       "202201207777"

/* Type of power sources available for the device.
 * For possible values see section 3.2.2.2.8 of ZCL specification.
 */
#define SWITCH_INIT_BASIC_POWER_SOURCE    ZB_ZCL_BASIC_POWER_SOURCE_BATTERY

/* Describes the physical location of the device (16 bytes).
 * May be modified during commisioning process.
 */
#define SWITCH_INIT_BASIC_LOCATION_DESC   "Home"

/* Describes the type of physical environment.
 * For possible values see section 3.2.2.2.10 of ZCL specification.
 */
#define SWITCH_INIT_BASIC_PH_ENV          ZB_ZCL_BASIC_ENV_UNSPECIFIED

#define TOGGLE_SWITCH					DK_BTN3_MSK

/* Nordic PWM nodes don't have flags cells in their specifiers, so
 * this is just future-proofing.
 */
#define FLAGS_OR_ZERO(node) \
	COND_CODE_1(DT_PHA_HAS_CELL(node, pwms, flags), \
		    (DT_PWMS_FLAGS(node)), (0))


#ifndef ZB_ED_ROLE
#error Define ZB_END_DEVICE_ROLE to compile enddevice source code.
#endif

static void switch_send_on_off(zb_bufid_t bufid, zb_uint16_t on_off);

LOG_MODULE_REGISTER(app);

/** 
 * Placeholder for the bulb context 
 * Stores all settings and static values.
 **/
typedef struct 
{
	zb_zcl_basic_attrs_ext_t         basic_attr;
	zb_zcl_identify_attrs_t          identify_attr;
	zb_zcl_scenes_attrs_t            scenes_attr;
	zb_zcl_groups_attrs_t            groups_attr;
 	zb_zcl_on_off_attrs_t            on_off_attr;
} on_off_device_ctx_t;
/* Zigbee device application context storage. */
static on_off_device_ctx_t dev_ctx;

ZB_ZCL_DECLARE_IDENTIFY_ATTRIB_LIST(
	identify_attr_list,
	&dev_ctx.identify_attr.identify_time);

ZB_ZCL_DECLARE_GROUPS_ATTRIB_LIST(
	groups_attr_list,
	&dev_ctx.groups_attr.name_support);

ZB_ZCL_DECLARE_SCENES_ATTRIB_LIST(
	scenes_attr_list,
	&dev_ctx.scenes_attr.scene_count,
	&dev_ctx.scenes_attr.current_scene,
	&dev_ctx.scenes_attr.current_group,
	&dev_ctx.scenes_attr.scene_valid,
	&dev_ctx.scenes_attr.name_support);

ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST_EXT(
	basic_attr_list,
	&dev_ctx.basic_attr.zcl_version,
	&dev_ctx.basic_attr.app_version,
	&dev_ctx.basic_attr.stack_version,
	&dev_ctx.basic_attr.hw_version,
	dev_ctx.basic_attr.mf_name,
	dev_ctx.basic_attr.model_id,
	dev_ctx.basic_attr.date_code,
	&dev_ctx.basic_attr.power_source,
	dev_ctx.basic_attr.location_id,
	&dev_ctx.basic_attr.ph_env,
	dev_ctx.basic_attr.sw_ver);

/* On/Off cluster attributes additions data */
ZB_ZCL_DECLARE_ON_OFF_ATTRIB_LIST(
	on_off_attr_list,
	&dev_ctx.on_off_attr.on_off);

ZB_HA_DECLARE_ON_OFF_OUTPUT_CLUSTER_LIST(on_off_output_clusters,
    on_off_attr_list, basic_attr_list, identify_attr_list, groups_attr_list,
    scenes_attr_list);

ZB_HA_DECLARE_ON_OFF_OUTPUT_EP(on_off_output_ep, HA_SWITCH_ENDPOINT, on_off_output_clusters);

ZB_HA_DECLARE_ON_OFF_OUTPUT_CTX(on_off_output_ctx, on_off_output_ep);

/**@brief Callback for button events.
 *
 * @param[in]   button_state  Bitmask containing buttons state.
 * @param[in]   has_changed   Bitmask containing buttons
 *                            that have changed their state.
 */
static void button_changed(uint32_t button_state, uint32_t has_changed)
{
	zb_ret_t zb_err_code;
	zb_uint16_t cmd_id = ZB_ZCL_CMD_ON_OFF_ON_ID;
	zb_err_code = zb_buf_get_out_delayed_ext(switch_send_on_off, cmd_id, 0);
	ZB_ERROR_CHECK(zb_err_code);
}

/**@brief Function for initializing LEDs and Buttons. */
static void configure_gpio(void)
{
	int err;

	err = dk_buttons_init(button_changed);
	if (err) {
		LOG_ERR("Cannot init buttons (err: %d)", err);
	}
}

/**@brief Function for sending ON/OFF requests to the network / co-ordinator.
 *
 * @param[in]   bufid    Non-zero reference to Zigbee stack buffer that will be
 *                       used to construct on/off request.
 * @param[in]   cmd_id   ZCL command id.
 */
static void switch_send_on_off(zb_bufid_t bufid, zb_uint16_t cmd_id)
{
	LOG_INF("Send ON/OFF command: %d", cmd_id);
	zb_uint16_t coordinator_address = 0x0000;
	dev_ctx.on_off_attr.on_off = (zb_bool_t)ZB_ZCL_ON_OFF_IS_ON;				

	ZB_ZCL_ON_OFF_SEND_REQ(bufid,
				coordinator_address,
				ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
				HA_SWITCH_ENDPOINT,
				HA_SWITCH_ENDPOINT,
				ZB_AF_HA_PROFILE_ID,
				ZB_ZCL_ENABLE_DEFAULT_RESPONSE,
				cmd_id,
				NULL);
}

/**@brief Callback function for handling ZCL commands.
 *
 * @param[in]   bufid   Reference to Zigbee stack buffer
 *                      used to pass received data.
 */
static void zcl_device_cb(zb_bufid_t bufid)
{
	zb_uint8_t cluster_id;
	zb_uint8_t attr_id;
	zb_uint8_t endpoint_invoked;	
	zb_zcl_device_callback_param_t  *device_cb_param =
		ZB_BUF_GET_PARAM(bufid, zb_zcl_device_callback_param_t);
	
	endpoint_invoked = device_cb_param->endpoint;

	LOG_INF("%s id %hd", __func__, device_cb_param->device_cb_id);

	LOG_INF("EndPoint Called is %d ", endpoint_invoked);

	/* Set default response value. */
	device_cb_param->status = RET_OK;
	LOG_INF("ZB Callback started %c", bufid);	

	LOG_INF("%s status: %hd", __func__, device_cb_param->status);
}

/**@brief Zigbee stack event handler.
 *
 * @param[in]   bufid   Reference to the Zigbee stack buffer
 *                      used to pass signal.
 */
void zboss_signal_handler(zb_bufid_t bufid)
{
	/* No application-specific behavior is required.
	 * Call default signal handler.
	 */
	ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid));

	/* All callbacks should either reuse or free passed buffers.
	 * If bufid == 0, the buffer is invalid (not passed).
	 */
	if (bufid) {
		zb_buf_free(bufid);
	}
}

void error(void)
{
	while (true) {
		/* Spin forever */
		k_sleep(K_MSEC(1000));
	}
}

void main(void)
{
	int err;

	LOG_INF("Starting Switch example");

	/* Initialize */
	configure_gpio();
	err = settings_subsys_init();
	if (err) {
		LOG_ERR("settings initialization failed");
	}

	LOG_INF("Registering Device");
	/* Register callback for handling ZCL commands. */
	ZB_ZCL_REGISTER_DEVICE_CB(zcl_device_cb);

	LOG_INF("Setting Switch Context");
	/* Register dimmer switch device context (all the endpoints). */
	ZB_AF_REGISTER_DEVICE_CTX(&on_off_output_ctx);

	/* Initialize ZCL scene table */
	// zcl_scenes_init();

	/* Settings should be loaded after zcl_scenes_init */
	err = settings_load();
	if (err) {
		LOG_ERR("settings loading failed");
	}

	/* Start Zigbee default thread */
	zigbee_enable();

	LOG_INF("Switch example started");

	while (1) {
		// k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL));
	}
}

1. When the image is flashed in DK, it properly registers to the Zigbee2MQTT and send the correct response  - please see the the Part 1 in the snapshot below.  The Cluster is 'genOnOff, type 'readResponse' and json data {'OnOff':0}

2. After button is clicked - DK BTN3 in this case, the type changes to 'commandOn' with json data being empty - please see the Part 2 in the snapshot below.  It is obviously due to the macro ZB_ZCL_ON_OFF_SEND_REQ. But I would need the cluster and the payload sent just like # 1.  Which macro should I use to retain the type 'readResponse' for cluster 'genOnOff' and fill in the json data? This is for the OnOff Output ZCL

Parents
  • Hi,

    Can you clarify what you mean by the read response? Is this something the DK should send, or the coordinator? Is this as a response to the ON/OFF command, or are you thinking about the Read Attributes command?

    I see you are sending the ON/OFF command to the endpoint of the light switch. Is the endpoint on the coordinator also 12, so that the command is sent to the correct endpoint?

    Best regards,

    Marte

  • Hi Marte,

    Can you clarify what you mean by the read response? Is this something the DK should send, or the coordinator? Is this as a response to the ON/OFF command, or are you thinking about the Read Attributes command?

    1.    If you check the screenshot above (pasted the text below), it has this debug messages in Zigbee2Mqtt (Z2M). This is issued just when the DK connects to Z2M.  So the initial setup of the OnOff Cluster generates the type 'readResponse' from cluster genOnOff  and send to co-ordinator

    Debug Received Zigbee message from 'dev_board', type 'readResponse', cluster 'genOnOff', data '{"onOff":0}' from endpoint 12 with groupID 0

    However, when I press the button, as I explained in the above post, I call the macro 'ZB_ZCL_ON_OFF_SEND_REQ which generates the following. Looks like this call modifies the type to 'commandOn' and data payload is empty. So my question is there a macro which generates the same zigbee message which is called during initialization? This could be reused during button press and send to co-ordinator

    Debug Received Zigbee message from 'dev_board', type 'commandOn', cluster 'genOnOff', data '{}' from endpoint 12 with groupID 0

    2.  For the second point you asked

    I see you are sending the ON/OFF command to the endpoint of the light switch. Is the endpoint on the coordinator also 12, so that the command is sent to the correct endpoint?

    I am just sending the ON/OFF command to the co-ordinator. There is technically no LightSwitch.  The Z2M (running as a co-ordinator) just receives the Zigbee messages and converts to MQTT messages.  So it does not matter which endpoint the zigbee command from the DK is sent to.  As long as the messages is received by the co-ordinator (running Z2M) it it good. And this is what I am trying to indicate, during the initial connect when DK connects, the Zigbee Mesages generate has a correct 'type' - readResponse and 'data' {"onOff":0} , but after button press, I believe the Macro changes the type to 'CommandOn' and the data JSON is empty.  Hence, wanted to know how can the same method / macro be used which might be called during initial connect.

    Hope I am clear.  You may check the main.c for more details

  • Hi,

    Manju_rn said:
    So my question is there a macro which generates the same zigbee message which is called during initialization?

    To answer this I need to know what readResponse actually is. In the Zigbee specification you have different types of read responses, but there is nothing simply called read response, which is why I asked for a clarification as to what sort of read response this is. It would be better to know what you want to achieve with the read response. Do you want to read what the value of the OnOff attribute is, and if so on which device? Or is the goal to do something else? I have not been able to find a lot of documentation as to what specifically the readResponse in Zigbee2MQTT is, so knowing more about what it is you want to do would make it easier for me to figure out what command you can use.

    Manju_rn said:
    However, when I press the button, as I explained in the above post, I call the macro 'ZB_ZCL_ON_OFF_SEND_REQ which generates the following. Looks like this call modifies the type to 'commandOn' and data payload is empty

    This is because the macro ZB_ZCL_ON_OFF_SEND_REQ sends an On or Off command from the On/Off cluster. The parameter cmd_id decides which of the commands is sent, and in your code you are using the ID of the On command, so you are sending the On command, resulting in the type in Zigbee2MQTT being 'commandOn'.

    Manju_rn said:
    2.  For the second point you asked

    As for your second point the DK is implemented and acting as a light switch in your program, which is why i called it a light switch. It does, however, matter which endpoint the command is sent to if you are sending On/Off command to turn something on or off. But since you are saying that you want to get the read response I am not sure if sending the On command is actually what you want to do or not, so please specify what it is you want to achieve with this program.

    Best regards,

    Marte

  • I have not been able to find a lot of documentation as to what specifically the readResponse in Zigbee2MQTT is, so knowing more about what it is you want to do would make it easier for me to figure out what command you can use

    Please check the following code in the Zigbee2MQTT Converters. These converters basically a layer in Z2M which parses the Zigbee messages  https://github.com/Koenkk/zigbee-herdsman-converters/blob/master/converters/fromZigbee.js#L740

        on_off: {
            cluster: 'genOnOff',
            type: ['attributeReport', 'readResponse'],
            convert: (model, msg, publish, options, meta) => {
                if (msg.data.hasOwnProperty('onOff')) {
                    const property = postfixWithEndpointName('state', msg, model);
                    return {[property]: msg.data['onOff'] === 1 ? 'ON' : 'OFF'};
                }
            },
        },

    It looks for the Cluster 'genOnOff' with type 'readResponse' and the attribute of 'onOff".  This is written based on the ZCL specs for OnOff Cluster. 

    I realized that the reporting is not configured, I was of the assumption that the macro ZB_HA_DECLARE_ON_OFF_OUTPUT_EP would enable the reporting.  Anyway, I have configured the reporting like this.

    static void configure_reporting_locally(void)
    {
      zb_zcl_reporting_info_t rep_info;
      memset(&rep_info, 0, sizeof(rep_info));
    
      rep_info.direction      = ZB_ZCL_CONFIGURE_REPORTING_SEND_REPORT;
      rep_info.ep             = HA_SWITCH_ENDPOINT;
      rep_info.cluster_id     = ZB_ZCL_CLUSTER_ID_ON_OFF;
      rep_info.cluster_role   = ZB_ZCL_CLUSTER_SERVER_ROLE;
      rep_info.attr_id        = ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID;
    
      rep_info.u.send_info.min_interval = 0;
      rep_info.u.send_info.max_interval = 0;
      rep_info.u.send_info.delta.u8     = 1;
       
      rep_info.dst.short_addr = 0x0000 ; //Hex 
      rep_info.dst.endpoint   = 12 ;     //Decimal 
      rep_info.dst.profile_id = ZB_AF_HA_PROFILE_ID ;
    
      zb_zcl_put_reporting_info(&rep_info,ZB_TRUE);
    }
    
    void zboss_signal_handler(zb_bufid_t bufid) 
    {
    	zb_zdo_app_signal_hdr_t *p_sg_p = NULL;
    	zb_zdo_app_signal_type_t sig = zb_get_app_signal(bufid, &p_sg_p);
    	zb_ret_t status = ZB_GET_APP_SIGNAL_STATUS(bufid);
    
    	/* Update network status LED */
    	// zigbee_led_status_update(bufid, ZIGBEE_NETWORK_STATE_LED);
    
    	switch (sig) 
    	{
    		case ZB_BDB_SIGNAL_DEVICE_REBOOT:
    			/* fall-through */
    		case ZB_BDB_SIGNAL_STEERING:
    			/* Call default signal handler. */
    			ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid));
    			if (status == RET_OK) 
    			{
    				LOG_INF("Steering Completed. Going ahead with reporting configuration");
    				configure_reporting_locally();
    			}
    			break;
    
    		default:
    			/* Call default signal handler. */
    			ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid));
    			break;
    	}
    
    	if (bufid) 
    	{
    		zb_buf_free(bufid);
    	}
    }

    The above setting does not send any configuration details to Z2M.  Is there some code I need to call specifically to set the reporting?

    However, I have noticed that when I send the reporting configuration request from Z2M to DK, then the reporting get enabled.  However, this does not help as I want to configure the reporting from the device - DK in this case.

  • ZB_HA_DECLARE_ON_OFF_OUTPUT_EP

    Realized that there was a small change needed at Z2M to receive the reporting configuration, so the quoted method does indeed initalize the reporting. Hence, the method 'configure_reporting_locally" that was written is not really required to configure reporting.

    However, the default reporting takes the min interval value as 0, and the max interval value as 3600 (see the snapshot for Z2M). However, the intention was to enable enable reporting based on the value change, so the max interval value should be 0 I believe. 

    So I guess I will still have to use the configure_reporting_locally, but somehow the call zb_zcl_put_reporting_info(&rep_info,ZB_TRUE);  does not invoke any zigbee message.  Is there another method I could use to update the default reporting values of max and Min intervals?

  • Hi,

    Thank you for the link to the source code of the Zigbee2MQTT converter. This makes it clearer what it is you want.

    Manju_rn said:
    I was of the assumption that the macro ZB_HA_DECLARE_ON_OFF_OUTPUT_EP would enable the reporting

    ZB_HA_DECLARE_ON_OFF_OUTPUT_EP does not enable reporting. It only declares the endpoint for a device and defines a Simple Descriptor for the endpoint. This is necessary for the device to be able to report attributes, but it does not in itself configure attribute reporting. You can read more about this in the guide Adding ZCL clusters to application and in Zigbee stack API overview.

    Please see Configure reporting command sending and parsing to read more about configuring attribute reporting. Since you want to enable reporting on the DK this will be the server notifying the client that the server has configured attribute reporting and that it will report attribute values to the client. Thus, you should use the macros ZB_ZCL_GENERAL_INIT_CONFIGURE_REPORTING_CLI_REQ and ZB_ZCL_GENERAL_ADD_RECV_REPORT_CONFIGURE_REPORTING_REQ, and then send it with ZB_ZCL_GENERAL_SEND_CONFIGURE_REPORTING_REQ.

    I have earlier made an example of this with the measured value attribute in the Temperature cluster. You can see the implementation of the attribute configuration below:

    void configure_attr_reporting(zb_bufid_t bufid)
    {
        zb_uint8_t * cmd_ptr;
        zb_uint16_t dst_addr = 0x0000;
        zb_uint8_t dst_ep = 64;
        ZB_ZCL_GENERAL_INIT_CONFIGURE_REPORTING_CLI_REQ(bufid,
                                                        cmd_ptr,
                                                        ZB_ZCL_ENABLE_DEFAULT_RESPONSE);
        ZB_ZCL_GENERAL_ADD_RECV_REPORT_CONFIGURE_REPORTING_REQ(cmd_ptr,
                                                               ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID,
                                                               0);
        ZB_ZCL_GENERAL_SEND_CONFIGURE_REPORTING_REQ(bufid,
                                                    cmd_ptr,
                                                    dst_addr,
                                                    ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
                                                    dst_ep, 
                                                    MULTI_SENSOR_ENDPOINT,
                                                    ZB_AF_HA_PROFILE_ID, 
                                                    ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, 
                                                    NULL);
        NRF_LOG_INFO("Attribute reporting configured");
    }

    This should be called after the device has joined the network. In my example I called it with zb_buf_get_out_delayed() to allocate the out buffer:

    zb_buf_get_out_delayed(configure_attr_reporting);

    Please note that this example was created in nRF5 SDK, but the Zigbee stack is ZBOSS in both nRF Connect SDK and nRF5 SDK. The one in nRF Connect SDK is just a newer version than the one in nRF5 SDK at the moment, so the parts related to the ZBOSS API are the same or very similar in the two SDKs.

    Best regards.

    Marte

Reply
  • Hi,

    Thank you for the link to the source code of the Zigbee2MQTT converter. This makes it clearer what it is you want.

    Manju_rn said:
    I was of the assumption that the macro ZB_HA_DECLARE_ON_OFF_OUTPUT_EP would enable the reporting

    ZB_HA_DECLARE_ON_OFF_OUTPUT_EP does not enable reporting. It only declares the endpoint for a device and defines a Simple Descriptor for the endpoint. This is necessary for the device to be able to report attributes, but it does not in itself configure attribute reporting. You can read more about this in the guide Adding ZCL clusters to application and in Zigbee stack API overview.

    Please see Configure reporting command sending and parsing to read more about configuring attribute reporting. Since you want to enable reporting on the DK this will be the server notifying the client that the server has configured attribute reporting and that it will report attribute values to the client. Thus, you should use the macros ZB_ZCL_GENERAL_INIT_CONFIGURE_REPORTING_CLI_REQ and ZB_ZCL_GENERAL_ADD_RECV_REPORT_CONFIGURE_REPORTING_REQ, and then send it with ZB_ZCL_GENERAL_SEND_CONFIGURE_REPORTING_REQ.

    I have earlier made an example of this with the measured value attribute in the Temperature cluster. You can see the implementation of the attribute configuration below:

    void configure_attr_reporting(zb_bufid_t bufid)
    {
        zb_uint8_t * cmd_ptr;
        zb_uint16_t dst_addr = 0x0000;
        zb_uint8_t dst_ep = 64;
        ZB_ZCL_GENERAL_INIT_CONFIGURE_REPORTING_CLI_REQ(bufid,
                                                        cmd_ptr,
                                                        ZB_ZCL_ENABLE_DEFAULT_RESPONSE);
        ZB_ZCL_GENERAL_ADD_RECV_REPORT_CONFIGURE_REPORTING_REQ(cmd_ptr,
                                                               ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID,
                                                               0);
        ZB_ZCL_GENERAL_SEND_CONFIGURE_REPORTING_REQ(bufid,
                                                    cmd_ptr,
                                                    dst_addr,
                                                    ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
                                                    dst_ep, 
                                                    MULTI_SENSOR_ENDPOINT,
                                                    ZB_AF_HA_PROFILE_ID, 
                                                    ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, 
                                                    NULL);
        NRF_LOG_INFO("Attribute reporting configured");
    }

    This should be called after the device has joined the network. In my example I called it with zb_buf_get_out_delayed() to allocate the out buffer:

    zb_buf_get_out_delayed(configure_attr_reporting);

    Please note that this example was created in nRF5 SDK, but the Zigbee stack is ZBOSS in both nRF Connect SDK and nRF5 SDK. The one in nRF Connect SDK is just a newer version than the one in nRF5 SDK at the moment, so the parts related to the ZBOSS API are the same or very similar in the two SDKs.

    Best regards.

    Marte

Children
Related