Maximum payload LoRaWan

Just wondering:
What is the maximum length off an ASCII string (without any special chars) being able to get sent over the air?

I’m using an autonomo with an microchip LoraBee; but assuming it’s a LoRa protocol limitation instead of an hardware based limit.

So, on the lowest datarate SF12 I have 51 bytes to sent.

But bytes != characters right?

1 ASCII character == 1 Byte, unless you have UNICODE and then it will the 2 bytes. Keep mind that you have a duty cycle and are airtime is restricted, it is best to keep your payload as small as possible, e.g. avoid json strings and just 1 byte if you like to transmit data like a temperature reading.

Go to for here more information on many LoRaWan related topics …

Check. The dutycycle is known: speak for 1 second, be silent for 99 :smile:

I’m hitting the duty cycle-limit right now :frowning: Although I know LoRaWan is not suitable to be used in a real-time tracker situation, I thought I would give it a go.
A position string is being sent with intervals of 17s. The first 30 minutes go fine; but after that the duty-cycle-limit kicks in. (>12b>> is not being sent, but just some info for me)

>12b>>9041618373200|51.xxxxxx|5.9xxxxx|0.0|252|93|10|4153|
The device is busy. Sleeping for 10 extra seconds.
The device is busy. Sleeping for 10 extra seconds.
>12b>>9041618383000|51.xxxxxx|5.9xxxxx|0.0|252|121|9|4153|
The device is busy. Sleeping for 10 extra seconds.
>12b>>9041618390800|51.xxxxxx|5.9xxxxx|0.0|252|134|7|4153|
>12b>>9041618392500|51.xxxxxx|5.9xxxxx|0.0|252|124|8|4153|
The device is busy. Sleeping for 10 extra seconds.
The device is busy. Sleeping for 10 extra seconds.
>12b>>9041618402300|51.xxxxxx|5.9xxxxx|0.0|252|122|9|4153|
The device is busy. Sleeping for 10 extra seconds.
The device is busy. Sleeping for 10 extra seconds.
>12b>>9041618412100|51.xxxxxx|5.9xxxxx|0.0|252|100|9|4153|
>12b>>9041618413900|51.xxxxxx|5.9xxxxx|0.0|252|100|9|4158|
The device is busy. Sleeping for 10 extra seconds.
The device is busy. Sleeping for 10 extra seconds.
>12b>>9041618423700|51.xxxxxx|5.9xxxxx|0.0|252|137|7|4158|
The device is busy. Sleeping for 10 extra seconds.
The device is busy. Sleeping for 10 extra seconds.

So I’m not sending json, but a fairly long string.
To bad for this DutyCycle :frowning:

Perhaps you have ADR on, in which case the RN2483 falls back to a ‘lower speed’ due to missing acknowledge. You should init like below …

LoRaBee.initABP(loraSerial, devAddr, appSKey, nwkSKey, false); // last parameter = ADR switch it off

You can easily pack GPS data in a few bytes, I sent lat and lon in 2 32 bit unsigned integers (8 bytes) if you go for a little less accuracy you can do it in 6 bytes. Apply the same logic to the remaining bytes (timestamps 32 or 16 bits) etc etc

Hi,

This duty cycle limit is not a LoRaWAN constraint - its a sub-GHz limitation.

Hmm @w4e, that sounds very interesting, packing the data in integers instead of strings.

I’m a fairly n00b in this kind of programming; normally my work of field is PHP. So juggling with bits and bytes is fairly new :slight_smile:

In my payload I’ve got besides the lat/lng offcourse also the course, hdop number of sats and some more integers. Which I now convert to a string and then sent away.

The gps library spits out floats; how would convert eg 51.123456 to an u_int32?
And
How would i be able to concat these 5 or 6 integers while keeping the possibility to split them on my server?

@JDP: You’re absolutely correct; my bad.

The gps library spits out floats; how would convert eg 51.123456 to an u_int32?

uint32_t ulat = (uint32_t)(lat * 1000000);

you can create a struct to pack the data …

struct __attribute__((packed,aligned(1))) info {
uint32_t lat;
uint32_t lon;
etc

} payload;

LoRaBee.send(1, (const uint8_t *) &payLoad, sizeof(payload));

Use the same struct at the receiving side to unpack your data.

I use a slightly more complex approach, by defining this at the receiving end in a format string (stored in mongo)

“format” : [ { “offset” : 0, “type” : 4, “mul” : 1e-7, “descr” : “lat” }, { “offset” : 4, “type” : 4, “mul” : 1e-7, “descr” : “lon” }, { “offset” : 8, “type” : 4, “descr” : “lux” } ]

Here I define the offset into the payload, type of integer, multiplication factor and description.

Finally found some time to play with this struct datatype. But I’m experiencing difficiculties in stuffing the struct with my GPS data.

This is the function I call to produce the payload and sent it away to the debugSerial for now, for testing purpose:

void sentPayload()
{
   // lat/lng
  uint32_t ulat = (uint32_t)(gps.location.lat() * 1000000);
  uint32_t ulng = (uint32_t)(gps.location.lng() * 1000000);
  uint8_t uspeed = (uint16_t) (gps.speed.knots() * 10);

  //opbouwen van de payload struct
  struct attribute((packed,aligned(1))) info {
      uint32_t ulat;
      uint32_t ulng;
      uint32_t uspeed;
  } payload;

  debugSerial.println( (const uint8_t *) &payload );
}

But that results in an error:

t1:132: error: expected ';' before 'struct'
t1:138: error: 'payload' was not declared in this scope

The latter with a pointer to the payload var in the debugSerial. So I guess the construction of the struct is not good.
But where…

attribute should be __attribute__ with leading and trailing underscores, apologies that fell off in my earlier example.

debugSerial.println( (const uint8_t *) &payload )

You are ‘printing’ binary data will show not display anything readable,

Ah that makes a big difference :smile:

So just for my understanding: the struct combines the different integers to one packed ‘payload’.
What happens if one of the parts of the struct are smaller then anticipated? You said you have a 'format’json which takes the offset and a type.

[{ "offset" : 0, "type" : 4, "mul" : 1e-7, "descr" : "lat" }, { "offset" : 4, "type" : 4, "mul" : 1e-7, "descr" : "lon" }]

But what happens if the first item has less than 4? Or does the struct add some kind of padding to make sure it always takes 4?

An uint32_t or a 32 bit unsigned integer always takes 4 bytes (unsigned char) there is NO intelligent compressing to pack the information in fewer bytes depending on the value.

packed,aligned(1) ensures the structure is not aligned as it ideally should be for optimal perfomance (see here for an explanation on data alignment) this will help to find the bytes where you would expect them to be …

In gcc there is a function (offsetof) which helps you to find the offset of the members of a structure in case you are not sure.

Willem, if you’re around Roermond I’ll buy you a beer or coffee (depending on the time ;))!

Thanks for your answer!

if you’re around Roermond I’ll buy you a beer or coffee

Nope, near Amsterdam … but thanks for the offer