2

I'm using Heltec WiFi LoRa32 boards (ESP32-S3 + SX1262).

Could you please help me how to encode data e.g. from temperature and humidity sensor into binary or hexadecimal form - to make the LoRa packet length shorter? Similar to what LoRaWAN does.

For example, I have two values:

float temperature = 21.56;
float humidity = 76.21;

I use the official Heltec library for LoRa radio, I only transfer data via LoRa (not LoRaWAN), so it is necessary to make it work with the library function Radio.Send().

Radio.Send( (uint8_t *)txpacket, strlen(txpacket) ); //send the package out

I found this example and this tutorial.

I'm confused in this, so I would appreciate a parto of code example compatible with Heltec library for encoding and decoding compatible with Heltec library functions.

rzickler
  • 133
  • 1
  • 1
  • 7

3 Answers3

2

If you want to send both temperature and humidity in a single packet, the easiest way is to define the packet as a struct with two fields:

struct LoraData {
    float temperature;
    float humidity;
};

You can then send the raw bytes by typecasting the address of such a struct to uint8_t*. This, however, is generally not recommended, because it violates C++ type aliasing rules. You can circumvent this issue by defining a union:

union LoraPacket {
    LoraData data;
    uint8_t bytes[sizeof(LoraData)];
};

This represents an area of memory that can be interpreted as containing either the numeric data data, or an array of bytes. Then you can fill the data field and send the raw bytes:

void send_dummy_data()
{
    LoraPacket packet = {
        .data = {
            .temperature = 12.56,
            .humidity = 76.21
        }
    };
    Radio.Send(packet.bytes, sizeof packet);
}

At the other end, you do the same thing backwards: you fill in the bytes and read back the numeric data:

void rx_done(uint8_t *payload, uint16_t size, int16_t, int8_t)
{
    if (size != sizeof(LoraPacket)) {  // sanity check
        Serial.println("Bad packet size");
        return;
    }
    LoraPacket packet;
    memcpy(&packet.bytes, payload, size);
    Serial.print("temperature: ");
    Serial.println(packet.data.temperature);
    Serial.print("humidity: ");
    Serial.println(packet.data.humidity);
}
Edgar Bonet
  • 45,094
  • 4
  • 42
  • 81
0

Radio.Send( (uint8_t *)txpacket, strlen(txpacket) );

Noted that strlen(txpacket) is only applicable if the txpacket is a string. Since temperature is a floating point value, it should be sizeof(temperature)(see further explanation below).

I think there is a misunderstanding that this send a "shorter" data because you saw the uint8_t, but it is not the case. A single-precision floating point data is stored as a 4-byte data in according to IEEE754 format. What the RadioSend((uint8_t *) temperature, sizeof(temperature)) does is it simply cast the floating point value to a pointer of byte (i.e. uint8_t) that is point to the beginning of the temperature in memory so that it can send the data byte-by-byte, the sizeof(temperature) is equivalent to sizeof(float) so it is equal to 4. The data that going through the radio transmission is still 4-byte floating point value.

To send the temperature and humidity, you just need to send the temperature and humidity data as:

float temperature = 21.56;
float humidity = 76.21;

RadioSend((uint8_t ) temperature, sizeof(temperature)); RadioSend((uint8_t ) humidity, sizeof(humidity));

However, as point out by @jsotola, if you want, there is a way to reduce the data to be sent from 4-byte floating point to 2-byte int16_t by converting the float to int16_t by multiply the floating point value with 100. The converted data is only 2-byte long as an int16_t without losing the precision of the floating point (which has precision of 2 decimal points).

float temperature = 21.56;
float humidity = 76.21;

int16_t temperature_in_integer = (int16_t) temperature * 100; // integer 2156 int16_t humidity_in_integer = (int16_t) humidity * 100; // integer 7621

// send 2-byte each RadioSend((uint8_t ) temperature_in_integer, sizeof(temperature_in_integer)); RadioSend((uint8_t ) humidity_in_integer, sizeof(humidity_in_integer));

On the receiving end, the received data need to be divided by 100 to get back the actual temperature and humidity value.

If this is a little confuse to you, I would suggest you pick up a book of C or C++ and learn the foundation of data types, data casting and pointer.

hcheung
  • 1,933
  • 8
  • 15
0

The CayenneLPP library works well for this. See the examples provided.

dda
  • 1,595
  • 1
  • 12
  • 17