Inconsistent Electron sleep timing

Hi—I’m using System.sleep(SLEEP_MODE_DEEP, NumberOfSeconds); with a reasonable amount of success but I’m trying to get the Electron to wake very consistently at :15 and :45 past every hour (sort of arbitrary—any 30 minute regular interval should suffice for this application). Currently, the Electron publishes at roughly but very inconsistently ~ 33 – 37 minute intervals and I can’t quite figure out where the extra and inconsistent time is coming from.

I calculate NumberOfSeconds every single time the code executes, knowing that there could be inconsistencies in execution timing, by getting the start time, end time, and execution time (end_time-start_time), and calculating the sleep time as 1800 seconds minus what I think should be execution time.

I’m using SYSTEM_MODE(AUTOMATIC);—could it be the case that the inconsistency is coming from the Electron’s connection attempts which occur before setup() or loop()? Couldn’t find in the docs ‘where’ in the execution process/code the Electron would try to make the connection. Thanks in advance!

void setup() {
	start_time = millis(); // for calculating sleep time below

	// To print to screen over USB-Serial
	Serial.begin(9600);

	// Wait for a line to arrive, max this out for now
	Serial1.setTimeout(TIMEOUT_SEAPHOX_MS);

}

// Give SeapHOx arbitrary wake character then "glast" command. Then listen for response.
void loop() {

	// Clean out any residual junk in buffer and restart serial port
	Serial1.end();
	delay(1000);
	Serial1.begin(115200);
	delay(500);

	// Get data in file after current file pointer
	// Serial1.print("a");
	// delay(500);
	Serial1.println("glast");

	// Read response
	s = Serial1.readString();			// read response
	String s2 = s.replace("Error.txt f_read error: FR_OK\r\n", "");
	const char* s_args = s2.c_str();
	char* each_var = strtok(strdup(s_args), "\t");
	Serial.println(s_args);

	// Parse response
	parseSeapHOx(each_var);

	// Publish to cloud
	publishSeapHOx();

	// Turn off microcontroller and cellular
	exec_time_sec = (millis()-start_time)/1000;
	System.sleep(SLEEP_MODE_DEEP, SLEEP_TIME_SEC-exec_time_sec);
}
void publishSeapHOx(void){
	char data[100];
	int count_NC = 0;
	float cellVoltage = batteryMonitor.getVCell();
	float stateOfCharge = batteryMonitor.getSoC();

	// Should perhaps put this and Serial.print(data) into if statement (like parseSeapHOx, above)
	snprintf(data, sizeof(data), "%s,%s,%.3f,%.5f,%.5f,%.5f,%.5f,%.5f,%.5f,%.5f,%.02f,%.02f",
					 SeapHOx_Cell.Board_Date,
					 SeapHOx_Cell.Board_Time,
					 SeapHOx_Cell.Main_Batt_Volt ,
					 SeapHOx_Cell.V_FET_INT,
					 SeapHOx_Cell.V_FET_EXT ,
					 SeapHOx_Cell.V_Pressure,
					 SeapHOx_Cell.pHINT,
					 SeapHOx_Cell.O2,
					 SeapHOx_Cell.SBE37_Temp,
					 SeapHOx_Cell.SBE37_Salinity,
				 	 cellVoltage,
					 stateOfCharge);
					 // Also want seapHOx time/date and GPS

	Serial.println(data); // did we make it into here?

	// if (Particle.connected() == false) {
	// 	Serial.println("Wasn't Connected");
	// 	Particle.connect();
	// }

	Particle.publish(eventName, data, 60, PRIVATE);
	delay(4000); // wait for publish to go out before sleeping
}

Instead of using millis() as the offset, I’d rather use Time.local() and calculate the difference between that and the desired wake time each time anew.
Look here
Waking the photon from deep sleep at designated times

Especially with the Electron you may also need to consider the potentially long reconnection time in case of poor signal.

BTW, if you want to stick with millis() start_time should always be 0 since that is the time millis() starts off to count after a reset cutting out all the delay imposed by factors like the reconnection period before setup() is actually called.

1 Like

Thanks, @ScruffRTime.local() sounds way more robust for this purpose. I’ll give it a shot. Good point about start_time always being 0!

Your last statement helps me understand a bit about what’s causing the problem, too, which is still over my head but seems to be related to the embedded firmware dealing with the reconnection prior to calling setup().

Maybe it makes more sense in my case to use SYSTEM_MODE(SEMI_AUTOMATIC) or MANUAL to minimize the Electron’s workload prior to getting a proper start_time.

You could also use SYSTEM_THREAD(ENABLED) or put the initialisation of start_time into a STARTUP() call, which is run as early as possible - even before trying to connect.
But as said, not required for a millis() counter init, due to the way the counter gets initialised by the controller.

1 Like