Adafruit_PM25AQI (Air Particulate Sensor) Library killing me

I cant see anything in either of the libraries that would indicate that it is making the master (my Particle Boron) create a low to high transition. Does this happen automatically, or is there a way to force it (say, by calling Wire.endTransmission() at the end of the checking of that sensor)?

I have replaced the sensor with a BME280 and something else strange happens now. It will run fine for 6-24hrs, and then just... stop! I restart the device and it runs fine for a random amount of time (rarely more than 24hrs) and then the sensor goes on strike (wont report temp, humidity, or pressure).

That's what the interface implementation should do by itself.

This is often a side effect of using String objects.

1 Like

Oh damn... I love a good String... I use a string to build my publish payload via:

String IDB_payload;
    // Tags & Database
    IDB_payload = "{ \"tags\" : {\"influx_db\": \"" + IDB_Name;   // InfluxDB database name (set in constants)
    IDB_payload += "\", \"device\": \"" + IDB_deviceTagValue;     // device name (from EEPROM)
    IDB_payload += "\", \"location\": \"" + IDB_locationTagValue; // device location (set in constants)

    IDB_payload += "\", \"" + IDB_tag1Name + "\": \"" + IDB_tag1Value;
    IDB_payload += "\", \"" + IDB_tag2Name + "\": \"" + IDB_tag2Value;
    IDB_payload += "\", \"" + IDB_tag3Name + "\": \"" + IDB_tag3Value;
    IDB_payload += "\", \"" + IDB_tag4Name + "\": \"" + IDB_tag4Value;
    IDB_payload += "\", \"" + IDB_tag5Name + "\": \"" + IDB_tag5Value;

    // Values
    IDB_payload += "\"}, \"values\": {";
    // USE FORMAT:
    // IDB_payload += "\"data1Name\": " + String(data1Value);
    IDB_payload += "\"PM1.0_env\": " + String(data.pm10_env);
    IDB_payload += ", \"PM2.5_env\": " + String(data.pm25_env);
    IDB_payload += ", \"PM10_env\": " + String(data.pm100_env);
    IDB_payload += ", \"0.3um0.1L\": " + String(data.particles_03um);
    IDB_payload += ", \"0.5um0.1L\": " + String(data.particles_05um);
    IDB_payload += ", \"1.0um0.1L\": " + String(data.particles_10um);
    IDB_payload += ", \"2.5um0.1L\": " + String(data.particles_25um);
    IDB_payload += ", \"5.0um0.1L\": " + String(data.particles_50um);
    IDB_payload += ", \"50um0.1L\": " + String(data.particles_100um);
    IDB_payload += ", \"PM2.5_hourly_avg\": " + String(pm2_5hourly_avg);
    IDB_payload += ", \"PM10_hourly_avg\": " + String(pm10hourly_avg);
    IDB_payload += ", \"PM2.5_24hr_avg\": " + String(pm2_5daily_avg);
    IDB_payload += ", \"PM10_24hr_avg\": " + String(pm10daily_avg);

    IDB_payload += ", \"outsideTemp\": " + String(tempVal);
    IDB_payload += ", \"outsideHumid_relative\": " + String(humiVal);
    IDB_payload += ", \"outsideHumid\": " + String(absoluteHumiVal);
    IDB_payload += ", \"outsidePressure\": " + String(pressureVal);

    IDB_payload += ", \"noise_dBA\": " + String(soundSensor_dBA);
    IDB_payload += ", \"noise1hr_dBA\": " + String(soundSensor_Hourly_avg);

    IDB_payload += ", \"" + String(deviceName.name) + "Voltage\": " + String(voltage);

    IDB_payload += "}}";

    Particle.publish("Publish_to_IDB", IDB_payload, PRIVATE);

It resets to "" every loop before I reconstruct it, so I presumed it wouldn't be overwhelming the memory?

ā€œResettingā€ does not do any garbage collection and hence heap fragmentation will still be an issue.

1 Like

Whats the way around this if i need to use Strings for Particle.publish? Will it always be doomed to fragment and fail? Is char a better option, or does it suffer the same fate?

You can use good ol’ C-string (aka char arrays) just fine with any function that takes a String too.

For your string construction I’d use snprintf()

But you could also ā€œriskā€ using JSONBuffWriter :wink:

2 Likes

Thanks again ScruffR, I just read a few tutorials on snprintf() and it broke my mind… I tend to agree with this part of the JSONBuffWriter description!

Will have a play and see how I go…

I tried sloppily doing the same thing, just changing to char, but it wasnt happy with that. Looks like I have some work to do!

Thanks again!

Once you got the hang of it snprintf() isn’t that complicated

I’d do something like this

const char template[] = 
  "{ \"tags\" : {\"influx_db\": \"%s\""
  ", \"device\": \"%s\""
  ", \"location\": \"%s\""
  ", \"%s\": \"%d\""
  ", \"%s\": \"%.2f\""
  ...
  "}";
...
  char data[512];
  snprintf(data, sizeof(data)
          , template 
          , IDB_Name
          , IDB_deviceTagValue
          , IDB_locationTagValue
          , someIntTagName, someIntValue
          , someFloatTagName, someFloatValue
          , ...
          };
  Particle.publish("Publish_to_IDB", data, PRIVATE);
2 Likes

Update, took a little fiddling (it really hates when you specify the wrong variable type!) but it seems to be posting with:

    const char IDB_template[] =
        "{ \"tags\" : {\"influx_db\": \"%s\""
        ", \"device\": \"%s\""
        ", \"location\": \"%s\""
        "}"
        ", \"values\": {"
        "\"%s\": %d"        // value1
        ", \"%s\": %d"      // value2
        ", \"%s\": %d"      // value3
        ", \"%s\": %0.2f"   // value4
        ", \"%s\": %0.2f"   // value5
        ", \"%s\": %0.2f"   // value6
        ", \"%s\": %0.2f"   // value7
        ", \"%s\": %0.2f"   // value8
        ", \"%s\": %0.2f"   // value9
        ", \"%s\": %0.2f"   // value10
        ", \"%s\": %d"      // value11
        ", \"%s\": %0.2f"   // value12
        ", \"%s\": %0.2f"   // value13
        ", \"%s%s\": %0.2f" // value14
        "}}";

    char IDB_data[512];
    snprintf(IDB_data, sizeof(IDB_data),
             IDB_template, // refers to format above

             /////// TAGS ///////
             IDB_Name,             // Influx DB name
             IDB_deviceTagValue,   // device name
             IDB_locationTagValue, // device location
             // Spare tags (unlimited, but also update IDB_template[])
             //  "tag1", tag1Val,
             //  "tag2", tag2Val,
             //  "tag3", tag3Val

             /////// VALUES ///////
             "PM1.0_env", pm1Reading,                // value1
             "PM2.5_env", pm2_5Reading,              // value2
             "PM10_env", pm10Reading,                // value3
             "PM2.5_hourly_avg", pm2_5hourly_avg,    // value4
             "PM10_hourly_avg", pm10hourly_avg,      // value5
             "PM2.5_24hr_avg", pm2_5daily_avg,       // value6
             "PM10_24hr_avg", pm10daily_avg,         // value7
             "outsideTemp", tempVal,                 // value8
             "outsideHumid_rel", humiVal,            // value9
             "outsideHumid_pct", absoluteHumiVal,    // value10
             "outsidePressure", pressureVal,         // value11
             "noise_dBA", soundSensor_dBA,           // value12
             "noise1hr_dBA", soundSensor_Hourly_avg, // value13
             deviceName.name, "Voltage", voltage);   // value14

    Particle.publish("Publish_to_IDB", IDB_data, PRIVATE);

Thanks again, I hope the above really helps someone in the future.

Will let this run for a few days and see if it fixes the fragmentation. I also removed all other strings possible with the exception of those nested in publishes…

As I am not assigning them to a variable, am I ok doing something such as the below?

Particle.publish("EEPROM Update", "daily index reset to: " + String(storage.dailyReadings_index), PRIVATE);

This device will be positioned remotely, so just need to pop the odd piece of diagnostics to the console to check if something goes odd. The ā€œString(someInt)ā€ is the bit I’m now worried about… Am I right in assuming that if I’m not declaring an actual ā€œString variable;ā€ that i’m not actually storing the string, but rather just using the String() command to convert the int to a string for the purposes of publish?

That won't make a difference. The data is still stored on the heap as temporary object and hence will still cause heap fragmentation. I may/will take longer for the issue to reoccur but eventually it will do.

1 Like

Bah humbug…

Is there an alternative way to quickly get a numerical value into a publish without having to construct an sprintf for every little value?

You could use a global String object with enough space pre-reserved to prevent it from outgrowing it’s bounds (including any extras string literals you’d ever combine with your value) and reuse that over and over again.

But then you’d be at the same place as with snprintf() of having to use that intermediate variable to build your string with the extra caveat that you are forced to use a global variable while snprintf() would happily work with an automatic/local variable :wink:

After all, this doesn’t seem that cumbersome but is much saver

void foo() {
  char msg[64]; // declare it once, use it multiple times

  snprintf(msg, sizeof(msg), "daily index reset to: %d", storage.dailyReadings_index);
  // use msg
  snprintf(msg, sizeof(msg), "some text: %s", someText);
  // reuse msg
  ...
}
1 Like

Oh right, that actually doesnt look so bad… Let me see how I go with it.

Thank you Obi-wan!

Update, well, that was actually super easy! Works a charm!

    snprintf(msg, sizeof(msg), "daily index reset to: %d", storage.dailyReadings_index);
    Particle.publish("EEPROM Update", msg, PRIVATE);

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.