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

MQTT and GPS concurrent mode on Thingy:91

Hi,

I know that this topic has been raised here many times, and I did read all of those threads, however none of them seem to solve my problem. As many others, what I am trying to do is to combine mqtt_simple and gps samples in order to send GPS data via MQTT. My ncs tag is 1.1.0, modem firmware 1.1.0, and I am working on Thingy:91.

The algorithm I tried to imply is pretty simple and based on all the posts I found here regarding this topic, so basically after setting the modem to work in LTE-M and GPS system mode I set the PSM, connect to the MQTT client, get the location and try to send it via MQTT.

This is my main function: 

void main(void)
{
	int err;
        int counter = 0;
        nrf_gnss_data_frame_t gps_data;
	u8_t		      cnt = 0;
        
        char kibana_message[100];
        double latitude, longitude;
	printk("GPS and LTE application started\n");

        lte_lc_system_mode_set(LTE_LC_SYSTEM_MODE_LTEM_GPS);
        lte_lc_init();
        lte_lc_connect();
        lte_lc_normal();
        lte_lc_psm_req(true);

        init_app();
        client_init(&client);

        err = mqtt_connect(&client);
                if (err != 0) {
                        printk("ERROR: mqtt_connect %d\n", err);
                        while(1){
                            err = mqtt_connect(&client);
                            if (err == 0) {
                                    printk("Successfully reconnected \n");
                                    break;
                            } else {
                                    printk("ERROR: mqtt_connect %d\n", err);
                                    k_sleep(K_MSEC(2000));
                                    }
                            }
                }

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

	while (1) {

                while(1) {
                  do {
			} while (process_gps_data(&gps_data) > 0);
			if (!got_first_fix) {
					cnt++;
					printk("\033[1;1H");
					printk("\033[2J");
					print_satellite_stats(&gps_data);
					printk("\nScanning [%c] ",
									update_indicator[cnt%4]);
			}
			if (((k_uptime_get() - fix_timestamp) >= 1) &&
				(got_first_fix)) {
                              printk("\033[1;1H");
                              printk("\033[2J");
                              print_satellite_stats(&gps_data);
                              print_pvt_data(&last_fix);
                              printk("---------------------------------\n");
                              printk("\n");
                              //print_nmea_data();
                              printk("---------------------------------\n");
                              update_terminal = false;
                              
                              latitude = print_latitude(&last_fix);
                              longitude = print_longitude(&last_fix);
                             
                              k_sleep(K_MSEC(3000));
                              break;
                              }
			k_sleep(K_MSEC(500));
                }

                err = poll(&fds, 1, K_SECONDS(CONFIG_MQTT_KEEPALIVE));
		if (err < 0) {
			printk("ERROR: poll %d\n", errno);
		}

		err = mqtt_live(&client);
		if (err != 0) {
			printk("ERROR: mqtt_live %d\n", err);
		}

		if ((fds.revents & POLLIN) == POLLIN) {
			err = mqtt_input(&client);
			if (err != 0) {
				printk("ERROR: mqtt_input %d\n", err);
			}
		}

		if ((fds.revents & POLLERR) == POLLERR) {
			printk("POLLERR\n");
		}

		if ((fds.revents & POLLNVAL) == POLLNVAL) {
			printk("POLLNVAL\n");
                        
                        err = mqtt_connect(&client);
                        if (err != 0) {
                                printk("ERROR: mqtt_connect %d\n", err);
                                while(1){
                                    err = mqtt_connect(&client);
                                    if (err == 0) {
                                            printk("Successfully reconnected \n");
                                            break;
                                    } else {
                                            printk("ERROR: mqtt_connect %d\n", err);
                                            k_sleep(K_MSEC(2000));
                                            }
                                    }
                        }

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

                sprintf(kibana_message, "[{\"latitude\":%lf, \"longitude\":%lf}]", latitude, longitude);
                printk(kibana_message);
                struct mqtt_utf8 message;
                message.utf8 = (u8_t *)kibana_message;
                message.size = (u32_t) strlen(kibana_message);
                data_publish(&client, MQTT_QOS_0_AT_MOST_ONCE, message.utf8, message.size);
                k_sleep(K_MSEC(4000));

                
		
	}

err = mqtt_disconnect(&client);
                        if (err) {
                                printk("Could not disconnect MQTT client. Error: %d\n", err);
                        }

                        err = mqtt_live(&client);
                        if (err != 0) {
                                printk("ERROR: mqtt_live %d\n", err);
                        }
        

	
}

The lte_lc_system_mode_set is not necessary, as in fact the system mode is set in the project configuration. I also modified slightly the init_app() function (which comes directly from the gps sample) in a way that it is not callig the enable_gps() function. The print_latitude and print_longitude are functions I wrote to get those two values and store them in variables.

The result from that is that I get the GPS fix, but then fail to send it - this is the output from LTE Link Monitor:

(yes, I did cover my coordinates in Paint).

As you see, after getting the first fix the device for some reason thinks it is still connected to MQTT client, but it's not - the message never reaches the mqtt server. After that it falls into the reconnection loop, returning errors 61 and 12.

I do know that PSM works - I confirmed that with CEREG command output, as well as with the fact that GPS would not work without PSM enabled.

What I found out is that after commenting out this loop:

while(1) {
                  do {
			} while (process_gps_data(&gps_data) > 0);
			if (!got_first_fix) {
					cnt++;
					printk("\033[1;1H");
					printk("\033[2J");
					print_satellite_stats(&gps_data);
					printk("\nScanning [%c] ",
									update_indicator[cnt%4]);
			}
			if (((k_uptime_get() - fix_timestamp) >= 1) &&
				(got_first_fix)) {
                              printk("\033[1;1H");
                              printk("\033[2J");
                              print_satellite_stats(&gps_data);
                              print_pvt_data(&last_fix);
                              printk("---------------------------------\n");
                              printk("\n");
                              //print_nmea_data();
                              printk("---------------------------------\n");
                              update_terminal = false;
                              
                              latitude = print_latitude(&last_fix);
                              longitude = print_longitude(&last_fix);
                             
                              k_sleep(K_MSEC(3000));
                              break;
                              }
			k_sleep(K_MSEC(500));
                }

Which is taken straight from the GPS sample, 'everything' works fine - the GPS socket is initialized and the messages are sent succesfully with MQTT in the while loop, but of course there is no gps location found.

What I tried already as a solution attempt is:

  • closing the gps socket after getting the gps fix - there were the same errors
  • connecting to mqtt client after getting the gps fix and disconnecting before - nothing changed

I thought it might be the socket collision, but I used the nrf_close function to close the GPS socket after getting the fix (according to documentation it is supposed to clean all the resources related to the socket) with no positive result.

It also happened many times already, that the device was falling into boot loop at some point, sometimes after lte_lc_connect() function call, sometimes after mqtt_connect() function, but since sometimes it happens and sometimes not, I cannot associate it to any specific part of the program, but maybe it might be a clue to understand what is happening here.

I am aware of both the asset_tracker and udp_gps sample existence, however I would prefer much more to understand how this all works and why it doesn't, to be able to develop applications by myself, rather than spending days on trying to understand the asset_tracker, which is a bit complex and has a lot of features that I do not need. Besides I think the whole procedure here should be pretty straightforward and should just require setting the PSM to make the whole thing work.

I will be grateful for any advice or help.

Edit: By some printf debugging I managed to locate the function that returns the 12 error, and this is connect_request_encode function from mqtt_internal.h file. It is called within the client_connect function in mqtt.c library (none of those files was edited by me, they come along with the whole ncs package). Unfortunately from this point I cannot go any further, so my question is - when is the connect_request_encode returning error 12?

I also have doubts about what is the right algorithm to perform this whole operation.

Should the MQTT client connection happen before getting GPS fix and remain connected, or should I connect and disconnect MQTT client after getting GPS location?

Should the GPS be stopped after getting a fix? Or put in the GPS PSM?

Should the LTE PSM be deactivated after getting the GPS fix (although the MQTT data transmission works well withing the PSM active time)?

  • Hi Maciek,
    I am very sorry for the delay.
    First, I recommend upgrading to:

    NCS v1.2.0 and MFW v1.1.1.

    I recommend that you do not have everything in your main function.

    You should have separate threads for the MQTT and GPS in your application, and both sockets should be read/polled all the time to avoid any conflicts.


    I would recommend that you get the GPS fix before turning ON the LTE modem. 

    note: You can wake-up from PSM mode whenever you want, (and you do not need to disable PSM mode after a fix). 
    - GPS can also be running in eDRX intervals when the modem is in RRC IDLE mode.

    It will be released an updated sample in NCS that shows this much better, so if you can wait a bit I would recommend looking out for that sample.

    You can also utilize A-GPS now which will give you a much better TTFF on a cold start of the GPS. (this is showcased in GPS sample)

Related