sending numbers int and floats over lora radio

I am using an Adafruit feather 32uf lora, and am using the AirSpayce's Radiohead library as suggested in the adafruit tutorial.

How do you send a number and string together using the module? The 'send' command is

rf95.send((uint8_t *)batteryPacket, 20);

when batteryPacket is :

char batteryPacket[20] = "battery voltage is: "

This works fine. But how do you add a float or integer to this char array? It looks like itoa() is the most suggested. But I do not understand the syntax for this command.
If my battery voltage is a float 3.7, how do I send "battery voltage is: 3.7" ?
I have tried:

int batVal = batVoltage*100 
//which will give me approx 3700, then I can convert on the other end
//ideally I could just send float...
itoa(batVal, batteryPacket+10, 10);

But when I run

 Serial.println(batteryPacket);

it returns "battery voltage is: "

I am simply just trying to send a string over radio...
In python I would just simply do "battery voltage is:" + str(batVoltage)

EDIT: I'd make a little mistake in the first example, used a float rather than an int, my mistake - corrected, now.

You could look at snprintf(), this will allow you to build and insert values directly into a string using format specifiers such as %d, example:

  int num = 123;
  char someText[20] = "Value of num is";
  char stringOut[30]; // Make this a bit bigger for the additional bytes.

  // Build the output string and store it in stringOut.
  snprintf(stringOut, 30, "%s %d", someText, num);

  // Dump.
  Serial.begin(9600);
  Serial.println(stringOut);

Where the %s format specifier expands to a string and %d (or %i if you want to be old fashioned) to an int. The resulting string is written to stringOut - note parameter 2 of the snprintf() call specifies the length of the buffer we're writing to (stringOut) obviously to prevent overflow. Also worth noting that the format specifiers in the format string must reference any parameters in the given order, i.e:

  snprintf(stringOut, 30, "%s %d", num, someText);

Is a problem, since %s is first in the format string the next parameter is expected to be a string.

Few other ways you could do it, here's another, slightly cleaner example with snprintf():

  int num = 123;

  // We can embed the %d specifier in this string...
  char someText[20] = "Value of num is: %d";
  char stringOut[30];

  // This will yield the same result as the previous example.
  sprintf(stringOut, 30, someText, num);

Awesome, thank you for the great explanation. I think it is close, but it is outputting a square instead of text in the serial monitor? My serial begin baud rate is 9600, and so is my serial monitor setting. Any ideas?

Sounds strange - can you post your code?

void setup() 
{
  //waitForSerial(); --> for debugging
  pinMode(LED, OUTPUT);
  pinMode(RFM95_RST, OUTPUT);
  digitalWrite(RFM95_RST, HIGH);
  Serial.begin(9600);
  delay(100);

  // manual reset
  digitalWrite(RFM95_RST, LOW);
  delay(10);
  digitalWrite(RFM95_RST, HIGH);
  delay(10);

  while (!rf95.init()) {
    Serial.println("LoRa radio init failed");
    Serial.println("Uncomment '#define SERIAL_DEBUG' in RH_RF95.cpp for detailed debug info");
    while (1);
  }
  Serial.println("LoRa radio init OK!");

  // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM
  if (!rf95.setFrequency(RF95_FREQ)) {
    Serial.println("setFrequency failed");
    while (1);
  }
  Serial.print("Set Freq to: "); Serial.println(RF95_FREQ);
  
  // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on

  // The default transmitter power is 13dBm, using PA_BOOST.
  // If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then 
  // you can set transmitter powers from 5 to 23 dBm:
  rf95.setTxPower(23, false);
}
void loop()
{
  runTX()
}

void runTX()
//this function is for battery powered nodes. 
{
  //delay for X seconds, sleep while delaying
  //rf95.sleep();
  //Watchdog.sleep(5000);
  delay(2000);

  //measure battery pin//
  float measuredvbat = analogRead(VBATPIN);
  measuredvbat *= 2;    // we divided by 2, so multiply back
  measuredvbat *= 3.3;  // Multiply by 3.3V, our reference voltage
  measuredvbat /= 1024; // convert to voltage
  Serial.println(measuredvbat);
  int BatVal = measuredvbat*100;
  Serial.println(BatVal);

  //battery pin measurement complete//

  //create character array to send via radio. array must be large enough to hold biggest value
  char batteryValString[13] = "battery: %d";
  char batteryPacket[30];
  sprintf(batteryPacket, 30, batteryValString, BatVal);
  Serial.println(batteryPacket);

  //send battery level over lora
  delay(10);
  rf95.send((uint8_t *)batteryPacket, 30);
}

Here is code. All the other Serial.print look fine, and print in normal characters. The part that says:

  Serial.println(batteryPacket);

just prints a single square instead of any ascii characters

I think I see the problem, you are calling sprintf() as opposed to snprintf()

The 'n' in snprintf() means, basically - that the function allows us to specify the size of the buffer we're writing to. So sprintf() exists, is a function in this family and will also work, but it doesn't expect parameter 2 to be an integer (buffer size) and will, if given the chance, wreak havoc with undefined behaviour. The sprintf() function expects parameter two to be the actual format string.

You shouldn't use sprintf() as it's not safe, it's the same deal with strcpy() vs strncpy(), etc. All you need to do is change that function call to snprintf() and it should be fine.

That did it! Thanks, @thapthoptheep!

Fantastic!

Glad to help, mate. That snprintf() function is an awesome litle tool to have at your disposal.

Enjoy your evening.

ETA - was actually my fault, second example I used sprintf(), my bad!

Not a problem, you saved me hours of banging my head on the desk. Have a great evening as well!

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