Is it possible to publish an event or call a function to trigger the device vitals event?


#1

From what I’ve read from the docs, the only way to request new device vitals is through the API or from the device console.

I know I could use an event to trigger a webhook that would make a POST request to the Particle API to request new vitals, but this seems pretty cumbersome.

Is there a function in the firmware to send the device vitals event? If there was, I could make my devices subscribe to an event and publish the device vitals on command, or I could make a cloud function that would make my devices send the device vitals event.

PS: My ultimate goal is to get the device vitals into Losant in the least convoluted way possible.

Here’s how long the flow would look like for Losant to get the device vitals from a device:

Losant -> Particle Function -> Device -> Publish Webhook Trigger -> Webhook -> Particle API -> Device -> Publish Device Vitals -> Losant

It just feels weird having to use a webhook to make a request to the Particle API.

I guess I could also do:

Losant -> Particle API -> Device -> Publish Device Vitals -> Losant


#2

Ping @ScruffR @rickkas7


#3

Hit up @jeiden also.


#4

Or better yet, is there a way to access these vitals from within the firmware in a struct or something?


#5

This might be useful
https://docs.particle.io/reference/api/#refresh-device-vitals

I haven’t tried whether you can directly trigger this in a similar way to how you request the device name (which would be nice to have), but if it doesn’t you could always use a webhook.

I think this is the part of the system repo you may want to look at too, starting here


#6

Yes, you can query the diagnostics values from user firmware. I do that in the DeviceKeyHelperRK library to get the last connection error from diagnostics. The code to read out any value is here:

You can also use system_format_diag_data to get the whole block of JSON data. That would make it easy to have a subscription handler or function that gets the diagnostic data then publishes it.


#7

@rickkas7 — thanks for this! Perhaps we should add this to the documentation on Diagnostics to help future folks with this?


#8

I think that would be great.


#9

This is exactly what I’m looking for. How would I make a function to do that?

UPDATE:

I’m going to see if I can modify this:

Edit:
I’m having trouble parsing the JSON with SparkJson. I’ll post more in the morning.


#10

Here is my new code:

#include "Particle.h"
#include "SparkJson/SparkJson.h"

SYSTEM_THREAD(ENABLED);

namespace {

const Serial1LogHandler logHandler(115200, LOG_LEVEL_WARN, {
                { "app", LOG_LEVEL_ALL }
        });

const SerialLogHandler logHandler1(LOG_LEVEL_WARN, {
                { "app", LOG_LEVEL_ALL }
        });


unsigned logMillis = 0;
unsigned logCount = 0;

bool logDiagnosticData(void* appender, const uint8_t* data, size_t size) {
        Log.write(LOG_LEVEL_INFO, (const char*)data, size);
        return true;
}


bool jsonDiagnosticData(void* appender, const uint8_t* data, size_t size) {

        char *mutableData = strndup((const char *) data, size);

        Serial.println(mutableData);

/*

   StaticJsonBuffer<1000> jsonBuffer;
   JsonObject& root = jsonBuffer.parseObject(mutableData);

   if (!root.success()) {
    Serial.println("parseObject() failed");
      return true;
   }

   int netstat = atoi(root["net:stat"].asString());

   Serial.print(netstat);

 */
        //Log.write(LOG_LEVEL_INFO, (const char*)data, size);
        return true;
}

} // namespace

void setup() {
        logMillis = millis();
}

void loop() {
        if (millis() - logMillis >= 5000) {
                ++logCount;
                Log.printf(LOG_LEVEL_INFO, "%u: ", logCount);
                system_format_diag_data(nullptr, 0, 0, jsonDiagnosticData, nullptr, nullptr);
                Log.print(LOG_LEVEL_INFO, "\r\n");
                logMillis = millis();
        }
}

For some reason when mutableData is printed there are lots of newlines in the string, resulting in the output looking like this:

1: {
"
sys:uptime
"
:
5
,
"
net:stat
"
:
4
,
"
net:err
"
:
0
,
"
cloud:stat
"
:
2
,
"
net:dconn
"
:
0
,
"
cloud:err
"
:
0
,
"
cloud:dconn
"
:
0
,
"
net:rssi
"
:
-19456
,
"
pub:limit
"
:
0
,
"
coap:unack
"
:
0
,
"
sys:tram
"
:
83200
,
"
sys:uram
"
:
38312
,
"
net:connatt
"
:
1
,
"
net:dconnrsn
"
:
0
,
"
cloud:connatt
"
:
1
,
"
cloud:dconnrsn
"
:
0
,
"
net:sigstr
"
:
12287
,
"
net:sigqual
"
:
5780
,
"
net:sigqualv
"
:
1048576
,
"
net:at
"
:
1
,
"
net:sigstrv
"
:
-4980736
,
"
_
"
:
"

"
}

This makes it unparseable by SparkJson.

Is there a way to clean up mutableData by removing all the newlines?


#11

The problem is that jsonDiagnosticData is called with tiny segments of the JSON, sometime only a single character, building up the data until system_format_diag_data returns.

What you’ll want to do is append to a buffer all of the data you get in the callback, then process it all at once after system_format_diag_data returns.


#12

Could you show me the best way to do that?


#13

I created a library to make getting these values easier, and also include pointers to where the constants come from and the documentation for the values.