Lightweight wireless device log

For a new project I needed a lightweight, easy access, untethered and “server free” device log for debugging/monitoring, that is working online and offline and survives a reset. Not finding it here, I am sharing what I came up with.

The log has room for 30 entries each with a timestamp + 6 chars of info. When full the oldest entry is overwritten. It uses retained memory to survive a reset, but you could use EEPROM (or external FRAM/FLASH) to also survive power downs.

This limited approach allows it to be accessed as one string via a Particle.variable(), so it can be fetched from the Console (copy to editor or a new mail for better readability) or even better viewed directly in the mobile App.

It can also be Particle.publish()'ed in one go to an external service when a device get online again or similar.

It is only a few lines of code and has proven extremely useful, so I now add it to all my projects:

retained char dLog[622] = " ";      // Max 622 char log for Particle.variable()

void devLog(const char *message) {  // Log one new entry out of 30, with 20 chars each (timestamp + 6 char message + newline char)

	if(dLog[19] != 10 /*Newline char*/) for(int i=0;i<30;i++) snprintf(dLog + (i*20), 20+1, "____________ ______\n");    // Init device log if empty

    memmove(&dLog[0], &dLog[20], (29*20) + 1); // Move 29 entries overwriting the first to make room for new entry nr. 30               MMDDHH:MM:SS (message)
    if(Time.isValid()) snprintf(dLog+(29*20), 20+1, "%s %-6s\n", (const char *)Time.format(Time.now(), "%m%d%H:%M:%S"), message); // "092218:02:15 PIO_UP"
    else snprintf(dLog + (29*20), 20+1, "%010ums %-6s\n", millis(), message);                                                    // "0000509986ms START "
    dLog[29*20+19] = 10; // for too long lines %-6s\n above adds 7 chars?, so have to plug in a newline char afterwards
}

void setup() {
	Particle.variable("DeviceLog", dLog);
	Time.zone(+2); // Adapt to your region
	devLog("INIT"); // examples
	devLog("");
	devLog("Too wide");
	devLog(String(sizeof(dLog)) + "B");
}

Once details are debugged, I use it for monitoring by only logging “deviations” like (re-)starts, (dis-)connects, config changes, re-uploads, predefined errors.

Here an output example snippet from an Argon controlling my Heat-pump (From October 18 at 22:53 in the evening)

0000000542ms START 
101822:53:19 PIO_UP
101822:53:19 LO    
101822:53:36 >26.0 
101822:56:47 MED   
101900:03:16 LO    
101900:05:56 MED   
101900:06:07 HI

Before being connected time is unknown so it uses millis() instead. In this case I decided “PIO_UP” means Particle IO connected, and “>26.0” means target temperature received via a Particle.function().

I have used the log on firmware 1.5.2 on Argon, B523 and Photon. Note! If you try to use it with an earlier version (less than or maybe even with 1.5.0), in the Console you will just get a “true” instead of the log.

11 Likes

:+1: