Working with Bytes &float(MKRwan 1300)

I’m a completely newbie in Lora.
I have bought MKRwan 1300.
I don’t know how to send data sends data as a byte or series of bytes.
Would you mind telling/teaching me how to send multiple float data ex: (temperature) t=26.76 , (humidity)h=45.31?.

I have read the information from your site but I can understand.
https://www.thethingsnetwork.org/docs/devices/bytes/

float t=26.76;
byte payload[8];
payload[0] = (byte) (( t & 0xFF000000) >> 24 );
payload[1] = (byte) (( t & 0x00FF0000) >> 16 );
payload[2] = (byte) (( t & 0x0000FF00) >> 8 );
payload[3] = (byte) (( t & 0X000000FF) );

float h=45.31;
payload[4] = (byte) (( t & 0xFF000000) >> 24 );
payload[5] = (byte) (( t & 0x00FF0000) >> 16 );
payload[6] = (byte) (( t & 0x0000FF00) >> 8 );
payload[7] = (byte) (( t & 0X000000FF) );

Is this way correct? How you can deal with multiple float?

If you really want to use float, I’d do something like this:

float t = 26.76;
uint8_t payload[20];
uint8_t *p = (uint8_t *)&t;
int idx = 0;
payload[idx++] = p[0];
payload[idx++] = p[1];
payload[idx++] = p[2];
payload[idx++] = p[3];

Then “payload” contains your payload and idx is the length of your encoded data.

If you want to add more data, you can continue like:

float h = 45.31;
p = (uint8_t *)&h;
payload[idx++] = p[0];
payload[idx++] = p[1];
payload[idx++] = p[2];
payload[idx++] = p[3];

I’m assuming that float contains a 32-bit IEEE-754 number.
You can control endianness by swapping p[0] with p[3] and p[1] with p[2].
This is a bit tricky to decode on the receiver side.

Another encoding which is frequently used is raw integer, where you multiply your float by some scaling factor (e.g. 100), then round it to integer and encode that. So 26.76 could be encoded as 2676. Probably easier to decode on the other side.

Yet another way to encode it, is to use Cayenne, see Cayenne Docs
This has the advantage that it’s relatively standard and can be decoded using a built-in decoder on the TTN side. It is similar to direct integer encoding, adds a bit of overhead to indicate the type of data.

// temperature (unit of 0.1 degree)
int16_t tint = round(t / 0.1);
payload[idx++] = 3;
payload[idx++] = 103;
payload[idx++] = highByte(tint);
payload[idx++] = lowByte(tint);

// humidity (unit of 0.5%)
uint8_t hint = round(h / 0.5)
payload[idx++] = 4;
payload[idx++] = 104;
payload[idx++] = hint;

This is by far and away the simplest technique and easy to understand.

1 Like

I have a question about this:
What about sending the floats as one String with a delimiter “|” between the values?

float t = 26.76;
float h = 45.31;
String msg = String(t) + "|" + String(h); //build message string to send

And than in payload formatter something like this to get the values separated:

  data = data.split("|");

  return {
    temperature: data[0],
    humidity: data[1]
  };

Sending strings is deeply inefficient and is to be avoided but that has possibilities.

Pretty much all the code I’ve seen has something like:

float temperature = getTemp();
int tempToSend = (int) (temperature * 100);
payload[0] = highByte(tempToSend);
payload[1] = lowByte(tempToSend);

which will send two decimal places of temperature and at the other end:

temperature = ((payload[0] << 8) + payload[1]) / 100;

which gets the two bytes and turns it in to an int and then gets the decimal places back with the / 100.

If I sent a temperature of 26.77, I’d be sending two bytes using the way above, if I use a string, I’m sending 5 bytes, so 250% more space is used - airtime is precious and the larger the payload, the bigger the battery drain as well.

Oh, I wasn’t aware of that - I thought the amount to be transferred would be identical. Thanks for the hint!!

Close, but you’ve converted to a long (int32_t) not an int (int16_t) and I was just typing the code off the cuff, so it should actually be uint16_t

A int32_t is four bytes and is signed.

There is also the wrinkle that you need to add an offset if the temperature is ever likely to be below zero.

Thank you .
How about the code now?
by using MKrWan 1300 ,Can I access to TTN directly or do I need gateway device?
In the case of using the LoraWan gateway, do I need to connect the gateway to Wifi?

Code looks good.

Transmissions have to be heard by a gateway so you need one near by or have one of your own. Some gateways do connect via Wifi

In the ‘other platform’ aka Payload Formatter

It shifts the first number 8 bits to the left and then adds the second byte - so it’s reversing the split in to bytes that was done on the device. Google bit shift for Binary maths 5 otherwise known as 101.

I think that’s a mess and means you aren’t following the documentation and really do need to learn Binary 5 (ie 101).

Read here for Class

mqtt-node-red-for-large-or-small-decoders-howto
payload-formats-howto

That is a very good point. I just started experimenting with LoRa, and drained a battery very quick by sending all data as string (in my foolness together with description “Outside Temperature: 21,55 Celsius”.
Way too much …
As many newbies I also started with using examples as a base for my sketch. th LoRa send example for my Arduino MKRWAN 1300 board sends strings. Using your approach, and modify the payload, I got errors.

Can you show, how the sending part of the sketch should look like?

modem.beginPacket();
modem.print(payload);

?

This is derived from working code:

uint8_t payload[30];    // Allow for up to 30 byte payload, increase/decrease as appropriate
uint8_t payloadSize; 

// Take & process readings
float degC = readTemperatureTo2DP();
uint16_t tempToSend = (uint16_t) ((degC +100) * 100);

// Add bytes to payload
payload[0] = highByte(tempToSend);
payload[1] = lowByte(tempToSend);
payloadSize = 2;

// Transfer to modem
modem.beginPacket();
for (uint8_t c = 0; c < payloadSize; c++) {
  modem.write(payload[c]);
}
err = modem.endPacket(confirmed);


Passing one byte at a time could possibly be refined but the MKRWAN library using Templates and other sophistications isn’t something I want to mess with. It works, but it’s not the best DIY device around as it’s a bit pricey and hard to get below 40uA when asleep.

Thank you very much for taking the time to help a beginner, and for the explanation, it helped me a lot, I will try to implement this.

So you say, MKRWAN is not a good choice for DIY battery operated LoRa Sensor stuff?
What about this one: https://www.tindie.com/products/iotmcu/lora-radio-node-v10/

Thats a 433Mhz module, you sure thats the right frequency for your part of the World ?

Its also based on a ATmega328P, which can struggle memory wise with some sensor setups.

And a sleep current of 300uA is very poor.

Sorry, I got the wrong link. My version is a 868 MHz suitable for my Country.
So this is also not the best choice you say …

I see both 433 & 868Mhz appear out of stock saving you some pain! :wink: Pehaps start looking at the well documented/supported, and well known in the parts, LMIC-node implementation and its supported boards:-

created and curated by friend of TTN & fellow mod @bluejedi
Well covered by Leonel and others in posts across the forum (search is your freind), with other people adapting to alternate boards…

Not the best choice for free-range development. It’s OK if you only need one or two simple sensors on digital or analog, not much room left for any other libraries and as mentioned above, worse on battery performance.

Like all device/car/laptop/house/partner choices, it’s all about what you want to do.

So if you tell us what you want to do and how much hardware & software experience you have, the advice can be tailored to suit.

Well my hardware/software experience I would characterise as hobbist/beginner. I have some experience with aruino boards, and mainstream sensors (DHT22, DS2810, …) and already built some units for my smart home system, but all of them based on WIFI. Now I would like to extend my system for outside stuff, (greenhouse monitoring, soil temp and humidity monitoring, Water level monitoring in rainwater tanks and pond, and so on) where there is no WIFI coverage, therefore I started to look at LoRa.

Does that library support ATMega328P etc ?