Floating point numbers in Particle.publish()

I’d like to be able to pass about 6 floating point variables via Particle.publish(). However, I’m seeing various topics about sprintf(%f) not working. It seems that it will work for one loop through my program and then the program appears to halt. I’m guessing this is a memory issue that I’ve seen referenced in discussions.

Can anyone recommend another alternative to sprintf() to pass floating point numbers with 1 digit to the right of the decimal point?

Thanks!

sprintf() should not cause what you see (if used correctly ;-))

Can you show your code?

Hi @ScruffR, As with most learning hacks, this is a bit of a mess, but it still should work…I believe. That being said, it does work fine if ai1 is an integer and I use %u in the sprint.

Also, my Particle.subscribe() also does not seem to call doNothing – at least the lights don’t light up. I normally don’t get a response, unless I’m posting a brand new stream to Grovestreams.

#define publish_delay 30000
unsigned int lastPublish = 0;
char publishString[40];
int loopCounter = 0;
//int led2 = D7;
float ai1 = 1000.17;
int ai2 = 2000;
int ai3 = 3000;

void setup() {
  Serial.begin(9600);
  Serial.println("we're in setup()");
  for(int i=0;i<10;i++) {
    Serial.println("waiting " + String(10-i) + " seconds before we publish");
    delay(100);
  }
  Particle.subscribe("hook-response/grovestreams",doNothing);
  int led2 = D7;
  pinMode(led2, OUTPUT);
  digitalWrite(led2, HIGH);
  delay(1000);
  digitalWrite(led2, LOW);
  delay(1000);
  digitalWrite(led2, HIGH);
  delay(1000);
  digitalWrite(led2, LOW);
  delay(1000);
  digitalWrite(led2, HIGH);
  delay(1000);
  digitalWrite(led2, LOW);
  delay(1000);
  //lastPublish = millis() - publish_delay - 1;
}

void loop() {
    unsigned long now = millis();

    if ((now - lastPublish) < publish_delay) {
        // it hasn't been publish_delay seconds yet...
        //return;
    }
    else {
        if (loopCounter < 120){
            loopCounter = loopCounter + 1;
            Serial.println("Attempting webhook!");
            sprintf(publishString,"{\"ai1\":\"%f\",\"ai2\":\"%u\",\"ai3\":\"%u\"}",ai1,ai2,ai3);
            Particle.publish("grovestreams",publishString);
            ai1 = ai1 + 1.0;
            ai2++;
            ai3++;
            //Particle.publish("grovestreams","{\"george\":\"234.2345\"}");
            lastPublish = now;
            //sprintf(fred,"this is something %u",17);
        }

    }
}

void doNothing(const char *name, const char *data){
  int led2 = D7;
  pinMode(led2, OUTPUT);
  digitalWrite(led2, HIGH);
  delay(1000);
  digitalWrite(led2, LOW);
  delay(1000);
  digitalWrite(led2, HIGH);
  delay(1000);
  digitalWrite(led2, LOW);
  delay(1000);
  digitalWrite(led2, HIGH);
  delay(1000);
  digitalWrite(led2, LOW);
  delay(1000);
  return;
}

Try extending your publishString and limit the decimal places of your float by use of something like "%5.2f"

It seems that extending the publishString was the fix. I must have been overwriting something in memory and causing the problem. Thanks for your help!

Aside from the lazy coding with multiple declares of led2, is there anything wrong with how I’ve tried to set up my Particle.subscribe() and the associated doNothing()? I can see in the Dashboard that I’m getting a response from GroveStreams when I try sending an undefined stream with data. GroveStreams handles it well, but it does tell me that I was an undefined stream.

I have no experience with GroveStreams, but I would keep my event handler a lot more compact and definetly no delay(1000) in it.
I’d possibly only set a flag and store the data content for further processing which would then happen in loop().

OK, thanks. The only reason the code with outputs are in there was for troubleshooting – to give me some visual indication the function had been called.

In addition to @ScruffR's suggestion to use a fixed point display of those floats, you might also generally want to use snprintf to prevent overwriting the end of your buffers.

1 Like

I just tried to compile with that, but got an error. Do I need to include an additional library to have access to snprintf()?

Are you also passing in the length of the buffer as a parameter to snprintf? I’m able to get this example to compile without any includes:

void setup() {
  Serial.begin(9600);
  delay(2000);
  char buf[10];  // Room for 9 characters + 1 terminating null = 10
  snprintf(buf, 10, "%s", "abcd");
  Serial.println(buf);   // Prints "abcd"
  snprintf(buf, 10, "%s", "abcdefghi");
  Serial.println(buf);   // Prints "abcdefghi", uses all 10 bytes
  snprintf(buf, 10, "%s", "abcdefghijklmnopqrstuvw");  // Overflow?!
  Serial.println(buf);   // Nope, prints "abcdefghi"
}

Note that the buffer size must take into account an extra byte for the terminating null, so if you want N printable characters, you should allocate N+1 bytes.

1 Like

If you talk about errors it would safe us guessing if you quoted the respective error message.

@indraastra, thank you for your clarification. I apologize–I simply changed the function being called and did not include a length parameter. I assumed it was capable of determining the length of the buffer. Thanks.

@ScrufffR, point well made. Thanks.