Storing very infrequent data while Photon offline (not cloud connected)

@charrold303, I believe you CAN do retained char dev_name[12] = "Tomato_1". However, that only initializes the c-string. I believe @ScruffR was guiding you to use snprintf() to produce your publish string and to avoid using (bad and evil) Arduino Strings.

2 Likes

Also not sure if the %.s should be %s or not. I think the decimal is just used on Floats where the number after the decimal on the float %f. function just tells it how many zeros you want to display after the decimal.

For an Unsigned Integer, I just use %u

2 Likes

replaced the snprintf with the strcopy for the device name (dev_name) (thanks @ScruffR and @peekay123

removed the . in “%.s” (thanks @RWB (interesting side note - compiled without errors with the “.” so maybe it ignored it either way? Just an interesting note))

Subthread!

I am trying to combine the ideas of the snprintf formatting and the incrementing array to the char array, and the compiler clearly doesn’t like what I am doing. I suspect adding a string to my char array is not as simple as I think it is (or you illustrated here). Here is what I tried:

retained char offlinevals[1024];
retained int16_t globalindex = 0;
for(a = 0; a < 6; a = a + 1 ) {
int SMVolts = analogRead(as[a]);
  if (SMVolts < 4000) {
    String voltage = String(SMVolts);
    String publishdata = publishdata + "S" + a + "::" + voltage + "::";
  }
  else {
    String publishdata = publishdata + "S" + a + "::DC::";
  }
}
// store the reading in the array 
snprintf(offlinevals, sizeof(offlinevals), "%s", publishdata);  <- this threw all sorts of nasty errors about copying things that shouldn't be copied... Also I know it is silly to create a formatted string and then create a string with formatting, but I am trying... *sigh*
}

It would be better to get rid of the String objects altogether. You can’t use %s for String objects, it’s only for c-strings. Instead of this,

String voltage = String(SMVolts);
String publishdata = publishdata + "S" + a + "::" + voltage + "::";

Do something like this,

char publishdata[12];
snprintf(publishdata, sizeof(publishdata), "S%d::%d::", a, SMVolts);

It’s not clear to me why you have publishdata on both sides of the equal sign, so what I wrote might not be what you want. If you’re using publishdata as the data argument in a Partilce.publish(), that’s fine; you can pass a char array or a String object to that function.

1 Like

the publishdata = publishdata + “other stuff” was my attempt to concatenate the existing string with more data into a new string with the sam name. Is that not allowed?

If you want to use a String object as %s parameter in snprtintf() you need to provide its contents as (const char*) and my prefered way to do that is via type cast

snprintf(offlinevals, sizeof(offlinevals), "%s", (const char*)publishdata);
// but this would also work - less elegant IMHO
snprintf(offlinevals, sizeof(offlinevals), "%s", publishdata.c_str());

But this would defeat the whole purpose to use snprintf() to get rid of the heap fragmentation effect String objects have.
@Ric has shown how you’d do the string building the better way.

BTW, since you create a new instance of publishdata with each iteration of your loop, your publishdata = publishdata + ... will always ever add the new data to the newly created and hence empty string.

If you wanted to code what you verbally described, you’d do it this way

  String publishdata = "Data:"; // create a new string only once 
  for (int i=0; i<10;i++) {
    publishdata += String(i);
    publishdata += ", ";
  }

But as said, forget String and try to understand the power of snprintf(), strcpy() and strcat().
I view String objects as a crutch for non-technical coders but embedded programming calls for more skill and hence less “comfortable” but more powerful tools.

1 Like

Hey guys! I think I figured out the whole string thing finally (at least my code compiles - testing will occur later today after I finish this last question)

particle.publish - max payload is 255.
my “offline values char array” is 254 (just to be safe) -> retained char offlinevals[254];
so my question is this:

@ScruffR said in an earlier posting:

if (newValue < 4000) { pubarray[globalIndex++] = newValue; if (globalIndex > 1023) globalIndex = 0; // when buffer is full overwrite old data }

With a char array does this work the same, or do I need to use the strlen()? Essentially the issue is, when I go through enough offline data collections (6.8 to be exact based on my “worst case” length of data stream) I do not want it to bomb out when it gets to the 7th loop in “offline mode” because there is no space left in the array.

My thought was to use something like:

if (strlen(offlinevals) > 244) { <- if my array is close to full then:

  - do something to start at the beginning a-la what ScruffR said? Not sure this works since I am (finally) using strcpy() and strcat() to build up the contents of the char array
  strcat(offlinevals, payload) but start from position 0 not the end?;

  - switch to a second offline array? (I could conceivably have 3 or 4 before I create memory issues)
 currentarray = offlinevals2[254]; (I know that's not correct, just illustrating the idea)

  - nuke the array and start over? (least liked option, but possible)
  strcpy(offlinevals, "");

  - Something else that someone suggests?
}

Thanks for making me stick with the strxxx() commands, gang. It is not intuitive but it does work and I understand it a lot better now…

1 Like

@RWB Thanks for introducing me to Losant! I was using Ubidots for a little while and gave Losant a try this week. Although getting data into Ubidots is a little easier, the extremely powerful workflow options and dashboards in Losant make up for it. Pushing numerous variables in a webhook and decoding the json in the workflow is awesome. Not to mention I can set up watch dog timers to trigger an even if a device doesn’t report in x hours. My only complaint is a limit of 10 devices and 30 day data retention in the free version (compared to 20 devices and 90 days for Ubidots).

Thanks again

@adamg Yea man Losant is Superior to Ubidots, especially when it comes to “Pushing numerous variables in a webhook and decoding the json in the workflow”.

Their free tier of service is perfect for my testing, they give you 1 million publish events which allows me to send 220-byte updates every 15 seconds without coming close to running out of free data. Ubidots free account would run out way before that with their current offerings.

For others who have never used Losant here is a new tutorial that will show you how to get setup with Losant for the first time step by step.

@BrandonCannaday Is this the new Particle setup guide you were working on?

1 Like

@RWB we actually have a more formal guide being written right now. That article is an awesome guest post by Kevin Sidwar. It does make use of the new Particle Integration, so definitely a good resource for learning how to use it!

2 Likes