system_thread, modes, gps

We are using the AssetTracker to build a monitoring and tracking solution for a sprayer in the countryside. Everything seems to work fine except when there is no 2G coverage. In that case, we need to log the data to an SD card.

We have tried with differnet SYSTEM Modes (auto, semi and manual) and SYSTME_THREAD(ENABLED) and cant seem to get it to work. For example, if we define SYSTEM_THREAD(ENABLED) and Semi-auto, the GPS does not seem to work. We have tried connecting in the setup, in loop, with and without SYSTEM_THREAD and all combinations of modes and no luck.

Can you please provide us with some guidance or reference as to how to approach this problem?

Some code to look at would definitely help. System modes/threading shouldn’t influence GPS sensors, though the connection might be blocking if you haven’t accounted for it.

1 Like

Sure, please see below the code and thanks for your help.

Again, when there is no 2G connection , we need to write the data to an SDCard (instead of using MQTT to send it to our server). We have also tried connecting and using waitFor and that does not seem to work either.


#include "sd-card-library-photon-compat/sd-card-library-photon-compat.h"
#include "MQTT/MQTT.h"
#include "AssetTracker/AssetTracker.h"
#include <math.h>
#include <list>
#include <regex>
#define LEDON HIGH
#define LEDOFF LOW

using namespace std;
static float _hmc5883_Gauss_LSB_XY = 1100.0F;  // Varies with gain
static float _hmc5883_Gauss_LSB_Z  = 980.0F;   // Varies with gain
static int address = 0x1E; //0011110b, I2C 7bit address of HMC5883
FuelGauge fuel;
CellularDevice device;
const uint8_t chipSelectSD = A1;
const uint8_t mosiPin = A5;
const uint8_t misoPin = A4;
const uint8_t clockPin = A3;
int tiempo;
String entry;
String coord="No hay GPS";
MQTT mqttClient(server, 1883, callback);

long dataFrameNumber = 0;
int applicationState = 1;
int batteryState = 5;

char payload[255];
char Sat[255];
String payload2;
AssetTracker t = AssetTracker();

void setup() {
    //pinMode(valvula1, INPUT);
   // pinMode(valvula2, INPUT);
    //pinMode(valvula3, INPUT);
    // pinMode(motor, INPUT);
    t.begin();                          // Sets up all the necessary AssetTracker bits
    t.gpsOn();                          // Enable the GPS module. Defaults to off to save power.
    Serial.println("Entre en el setup");;
    pinMode(ledBateria, OUTPUT);
    pinMode(ledGPS, OUTPUT);
    pinMode(ledGPRS, OUTPUT);
    pinMode(caja_abierta, INPUT);
    memset(&device, 0, sizeof(device));
    device.size = sizeof(device);
    cellular_device_info(&device, NULL);
    Particle.function("motor", encender_motor);
    Particle.function("bomba", encender_bomba);
    Particle.function("gps", gpsPublish);
    Particle.function("tiempo1", tiempo_motor_apagado);
    Particle.function("tiempo2", tiempo_motor_apagado_valula_apagada);
    Particle.function("tiempo3", tiempo_motor_apagado_valvula_prendida);
    publicado = true;

    Serial.println("Termine Setup");


void loop() {

void transmitirGPS(int delay, int mot, int val){


    if(millis()-lastPublish > delay*1000){
        lastPublish = millis();
            stringstream ss(t.preNMEA());
            while( ss.good() )
                string substr;
                getline( ss, substr, ',' );
                result.push_back( substr );
            memset(payload, 0, sizeof payload);
            snprintf(payload, sizeof(payload), "{ \"time\": %d, \"imei\": \"%s\", \"gps\": \"%s\", \"dir\": %f, \"motorState\": %d , \"valvulaState\": %d, \"batState\": %f, \"cantSat\": %s, \"cerrada\": %d}", - 10800, device.imei, t.readLatLon().c_str(), desviacion_actual, mot,val, fuel.getVCell(),result[7].c_str(),digitalRead(caja_abierta));

You should be using the updated SDFat library instead of sd-card-library-photon-compat
For waitFor() to work reliably, you’d need SYSTEM_THREAD(ENABLED)

WIth the state of code you’ve got there (single threaded and AUTOMATIC) it’s no wonder your code does not run when there is no cloud connection - that’s per design.
You definetly should use SYSTEM_THREAD(ENABLED) and optionally SEMI_AUTOMATIC too, if it’s very likely to have no cellular connection.

Since you are not showing all of your code, there might well be some code hidden in your “ellipses” ([...]) that causes your trouble.

BTW: I’d put the Particle.function()/Particle.variable() registrations further up in setup().

Will move the registrations further up the in the setup, thanks!

When we uncommented SYSTEM_THREAD and SEMI_AUTOMATIC, we did a particle.connect on the loop section (I did not included in the code) and the waitfor did not seem to work or GPS. I will enable that code , try again and see what happens.

If you use SEMI_AUTOMATIC I’d do this

void loop()
  // var & function registration
  t.begin();                          // Sets up all the necessary AssetTracker bits
  t.gpsOn();                          // Enable the GPS module. Defaults to off to save power.
  // do the rest

@ScuffR thanks for your support, we are working in a very important project with great potential to scale and cannot seem to get it to work when there is no 2G connection.

I am confused by your last suggestion. You mentioned to use waitUntil() but when there is NO 2g connection we want to move on and write to the log to a SD (instead of sending it via MQTT). Therefore it seems we want to use waitFor which unfortunately does not seem to work with or without SYSTEM_THREAD. I am having similar problems than SYSTEM_MODE, SYSTEM_THREADING and loop(), waitFor(), waitUntil() except that for him at least without system thread it did work (at least came back after 327s instead of 60)

Sorry for that :blush:
Sure, you’d rather go for waitFor().
It’s known that the timeout can take considerably longer than the time set, but that’s due to the systematic cellular connection times. A normal connection attempt is allowed to take up to five minutes (300sec) and the cellular modem has to allow for that, so any timeout shorter than that might be “ignored” or extended to that minimum plus your set timeout AFAIK.

But if this is not acceptable, you can always drop any waiting and start off without connection and just check for Particle.connected() before you do anything that requires the cloud.


The AssetTracker library on GitHub was last updated Feb 21. I think that means the errors identified in this thread Asset Tracker erratic haven’t been fixed.

If so, the GPS library being used seems to be somewhat fragile. It might not take much of a reduction in how often it’s called to to cause it to never correctly parse a fix.

So if there’s stuff going on in your loop that limits much at all how often transmitirGPS is called, that could possibly the the problem.

I use a different library (TinyGPS++) in an app that polls other sensors and is successfully running with SYSTEM_THREAD(ENABLED). But - one of the biggest timing issues I had was ensuring that the round-robin of polling got back to the GPS quite frequently. This is necessary unless you park in a tight loop reading serial until you get a valid GPS sentence and only then go do other processing.

HTH, Mike

@Mike… thanks for your tip!

Looking at the date on Github of the last update of TinyGPS++ is 3 years ago, is this correct? In that case the Assettracker library seems to be more updated.

I tried the particle-electron-gps-streamer example that uses TinyGPS++ but did not work, I suppose it has to do with the fact that they do not use an Assettracker but the UltimateGPS breakout (probably something with the pins). Do you have a sample working code with TinyGPS++. When you say that the round robin-polling got back to the GPS quite frequently what is it for you in seconds frequently?

In any event, in addition to the GPS problem, I still have not been able to figure out how to get my code work when there is NO 2G service (with or without SYSTEM_THREAD, and different MODES).

Hi @Galluta - most welcome.

Re TinyGPS++ age vs AssetTracker:
It’s not so much the age of the libraries as it is the stability of them. @jmccorm looks to have demonstrated that there are significant errors in the Assetracker library. It’s a long thread that’s referenced above but has good info. AFAIK the TinyGPS++ library has no such history of errors. For me, it’s been rock solid. I’ve run a Photon monitoring a GPS for weeks at a time and correctly processed millions of GPS sentences with that library.

Re TinyGPS++ and UltimateGPS:
They definitely will work together. I’ve go an UltimateGPS here somewhere and am using a GTOP chipset (same brand as Ultimate GPS) in my current solution.

Re how often I poll:
At the moment the loop checks the serial port connected to the GPS about every 50 milliseconds and will run a tight loop parsing any characters in the buffer each time. Since all I’m interested in from the GPS is the position fix, I’ve commanded the GPS to only issue the RMC sentence. Therefore I know the buffer will only have GPS sentences in it that contain data I want.
Now, every ten seconds or so I take a temperature reading which could result in the code not getting back to the GPS for 750 - 1000 ms. It seems to handle that just fine.

I have the code running on an Electron with only SYSTEM_THREAD enabled and auto for the cloud. As long as I wrap any call that might talk to the cloud inside a test for Particle.connected() the code doesn’t hang. I’ve run it more on the Photon, true. But the Electron seem to be fine with 24-48 hour test runs.

Finally, re example code:
Sadly, the GPS code is all enmeshed with the rest of the application code. I can’t readily extract it. However, there’s a simple looking example here: Example TinyGPS. TinyGPS++ is a newer version of TinyGPS but this should let you see some working code.
It occurs to me that all I really use in TinyGPS++ is the position parsing. There may be bugs lurking elsewhere; can’t say.


@MikeWhitten …Thanks a lot for your detailed email, will try your suggestions as well as @ScruffR Its great to get so much support from the community!