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.

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!!

Thank you very much.
I was trying to write a code using your method.
is it correct?

#include <MKRWAN.h>
LoRaModem modem;
#include "arduino_secrets.h"
#include <Wire.h>
#include "Adafruit_SHT31.h"
bool enableHeater = false;
uint8_t loopCnt = 0;
Adafruit_SHT31 sht31 = Adafruit_SHT31();

String appEui = SECRET_APP_EUI;
String appKey = SECRET_APP_KEY;
void setup() {

  while (!Serial)
    delay(10);     // will pause Zero, Leonardo, etc until serial console opens

  Serial.println("SHT31 test");
  if (! sht31.begin(0x44)) {   // Set to 0x45 for alternate i2c addr
    Serial.println("Couldn't find SHT31");
    while (1) delay(1);
  }

Serial.begin(115200);
while (!Serial);

// change this to your regional band (eg. US915, AS923, ...)


if (!modem.begin(EU868)) {
Serial.println("Failed to start module");
while (1) {}

};

Serial.print("Your module version is: ");
Serial.println(modem.version());
Serial.print("Your device EUI is: ");
Serial.println(modem.deviceEUI());
int connected = modem.joinOTAA(appEui, appKey);

if (!connected) {

Serial.println("Something went wrong; are you indoors? Move near a window and retry");

while (1) {}

}
modem.minPollInterval(60);
}
void loop() {
// read the value from the sensor:

uint8_t payload[8];
float t= sht31.readTemperature();
float h = sht31.readHumidity();

  if (! isnan(t)) {  // check if 'is not a number'
    Serial.print("Temp *C = "); Serial.println(t);
    } 
   if (! isnan(h)) {  // check if 'is not a number'
   Serial.print("Hum. % = ");  Serial.println(h);
    }

byte payload[8];
int16_t u16_Tmp, u16_Hmd;

u16_Tmp=(int)100.0*t;    // transfer float to int32_t with scale 100
u16_Hmd = (int)100.0*h;    // transfer float to int32_t with scale 100

byte high_byteT,low_byteT,high_byteH,low_byteH;

payload[0] = highByte(u16_Tmp);
high_byteT= (payload[0] ,HEX);
payload[1] = lowByte(u16_Tmp);
low_byteT = (payload[1] ,HEX);

Serial.println("highByteT");
Serial.println(high_byteT); 
Serial.println("lowByteT");
Serial.println(low_byteT);  

payload[2] = highByte(u16_Hmd);
high_byteH = (payload[2] ,HEX);
payload[3] = lowByte(u16_Hmd);
low_byteH = (payload[3] ,HEX);

Serial.println("highByteH");
Serial.println(high_byteH);  
Serial.println("lowByteH");
Serial.println(low_byteH);  



// scale the reading and fit into 1 byte


byte payload = ;

Serial.print("Scaled value = " );
Serial.println(scaledValue);

delay(1000);

modem.beginPacket();
modem.write(payload);
int err = modem.endPacket(false);
if (err > 0) {
Serial.println("Data Sent");
} else {
Serial.println("Error");
}
delay(100000 * 60);
}

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

Thank you.
temperature = ((payload[0] << 8) + payload[1]) / 100;
Where I should write this line? in my code or the other platfrom ?

payload[0] << 8+ payload[1]
Would you mind explaining this line?

At the end I will send 4 byte for temperature , Right?

What if I send data as following:
int tempToSend = (int) (temperature * 100);
payload[0] = highByte(tempToSend);

then
temperature = payload[0] / 100;
What do you think?

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).

in Arduino:
float temp =28.94;
uint16_t send_Temp=(uint16_t)Soil_T*100;
send_Soil_T=2894;
msg[0] = (send_Temp>> 8) & 0xFF; // highest byte
msg[1] = (send_Temp) & 0xFF; // lowest byte
In server:
send_Temp=send_Temp/100;
Is this code in the server is correct?
Would you mind telling the main differences between classes A,B and C?
Which IoT platform beside things network where I can Decode message inside it ?

Read here for Class

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