This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

How to code one-shot mqtt publish function?

I'm trying to make a one-shot mqtt function. The process is below

- connect
- publish
- disconnect

Then I coded like below. I show only the core code.

static u8_t payload_buf[CONFIG_MQTT_PAYLOAD_BUFFER_SIZE];

/**@brief Initialize the file descriptor structure used by poll.
 */
static int fds_init(struct mqtt_client *c)
{
	if (c->transport.type == MQTT_TRANSPORT_NON_SECURE) {
		fds.fd = c->transport.tcp.sock;
	} else {
#if defined(CONFIG_MQTT_LIB_TLS)
		fds.fd = c->transport.tls.sock;
#else
		return -ENOTSUP;
#endif
	}

	fds.events = POLLIN;

	return 0;
}

int8_t poll_and_check_rcv_data(u32_t interval_msec){
	int8_t err = poll(&fds, 1, interval_msec); // Check if any data comes through LTE-M. When it is waiting for an incoming data, it sleeps
	if (err < 0) {
		SEGGER_RTT_printf(0,"ERROR: poll %d\n", errno);
		return -1;
	}

	/* Check if data is received through LTE-M */
	if ((fds.revents & POLLIN) == POLLIN) { // If get data
		err = mqtt_input(&client);
		if (err < 0) {
			SEGGER_RTT_printf(0,"ERROR: poll %d\n", errno);
			return -1;
		}
	}
	if ((fds.revents & POLLERR) == POLLERR) {
		SEGGER_RTT_printf(0,"POLLERR\n");
		return -1;
	}
	if ((fds.revents & POLLNVAL) == POLLNVAL) {
		SEGGER_RTT_printf(0,"POLLNVAL\n");
		return -1;
	}

	return 0;
}


int8_t send_one_shot_mqtt_msg(enum mqtt_qos qos, u8_t *data, size_t len, char *topic){
	int err = 0;

	err = mqtt_connect(&client);
	if (err != 0) {
		SEGGER_RTT_printf(0,"ERROR: mqtt_connect %d\n", err);
		return -1;
	}
	SEGGER_RTT_printf(0, "after mqtt_connect\n");

	err = fds_init(&client);
	if (err != 0) {
		SEGGER_RTT_printf(0,"ERROR: fds_init %d\n", err);
		return -1;
	}

	err = poll_and_check_rcv_data(K_SECONDS(10)); // Wait for CONNACK
	if (err != 0) {
		SEGGER_RTT_printf(0,"ERROR: poll_and_check_rcv_data %d\n", err);
		return -1;
	}

	err = data_publish(&client, qos, data, len, topic);
	if(err < 0){
		SEGGER_RTT_printf(0,"fail sending reset message\n");
	}
	
	err = poll_and_check_rcv_data(K_SECONDS(5));
	if (err != 0) {
		SEGGER_RTT_printf(0,"ERROR: poll_and_check_rcv_data %d\n", err);
		return -1;
	}

	err = mqtt_disconnect(&client);
	if (err) {
		SEGGER_RTT_printf(0,"Could not disconnect MQTT client. Error: %d\n", err);
		return -1;
	}
	
	err = poll_and_check_rcv_data(K_SECONDS(3));
	if (err != 0) {
		SEGGER_RTT_printf(0,"ERROR: poll_and_check_rcv_data %d\n", err);
		return -1;
	}

	return 0;
}

void main(void)
{
	/* LTE set up*/
#if defined(CONFIG_PROVISION_CERTIFICATES)
	provision_certificates();
#endif
	modem_configure();
	
	while (1) {
	    k_sleep(K_SECONDS(60));
	    snprintf(payload_buf, 15, "{\"bat\":%d}", 10);
    	err = send_one_shot_mqtt_msg(MQTT_QOS_1_AT_LEAST_ONCE, payload_buf, strlen(payload_buf), CONFIG_MQTT_PUB_TOPIC);
    	if (err != 0){
    		SEGGER_RTT_printf(0,"Error: send_one_shot_mqtt_msg: %u\n", err);
    		return -1;
    	}
	}
}

Do I have to execute fds_init in send_one_shot_mqtt_msg everytime it publish a message on MQTT?

Should I omit fds_init? 

I really don't understand what fds_init does. 

I would appreciate it if you help me.

Parents
  • Hello everyone,

    I'm doing a routine quite like Yusuke, and would like to share my experience if others have the same issues.

    I am only calling the fds_init once in the setup and polling works fine. I get retained messages on subscribed topics, and get ack on sent my messages.

    My one-shot-function is otherwise similar to Yusukes. However, I had problems with "Failed to open socket, error: 23" after several connections (this also prevented me from getting cell location from nRF Cloud).

    It seems the mqtt_disconnect-function does not close the socket, and limitations here cause trouble. I am now calling mqtt_abort after mqtt_disconnect, and this solves the issue for me.

    Description of mqtt_abort:
    "API to abort MQTT connection. This will close the corresponding transport without closing the connection gracefully at the MQTT level (with disconnect message)."

    Combining these two seems to work fine, enabling "one shot mqtt" with the mqtt.c library. Another solution could be to use the BSD library (https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.4.2/nrfxlib/bsdlib/README.html)

Reply
  • Hello everyone,

    I'm doing a routine quite like Yusuke, and would like to share my experience if others have the same issues.

    I am only calling the fds_init once in the setup and polling works fine. I get retained messages on subscribed topics, and get ack on sent my messages.

    My one-shot-function is otherwise similar to Yusukes. However, I had problems with "Failed to open socket, error: 23" after several connections (this also prevented me from getting cell location from nRF Cloud).

    It seems the mqtt_disconnect-function does not close the socket, and limitations here cause trouble. I am now calling mqtt_abort after mqtt_disconnect, and this solves the issue for me.

    Description of mqtt_abort:
    "API to abort MQTT connection. This will close the corresponding transport without closing the connection gracefully at the MQTT level (with disconnect message)."

    Combining these two seems to work fine, enabling "one shot mqtt" with the mqtt.c library. Another solution could be to use the BSD library (https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.4.2/nrfxlib/bsdlib/README.html)

Children
No Data
Related