Heltec LoRa 32 v3.2: Receive a Structure Variable w/ heltec_unofficial library

Hi,
I am a beginner at C++. I have looked at several examples from various forums and websites and I am caught in a vicious circle. Either I find a complete example that looks like it does do what I want, but doesn't compile, or it does compile but doesn't do what I want, and I am not knowledgeable enough to make the necessary mods, or it does but the code is incomplete and I can't seem to fill the missing part correctly.
I have come up with the sending code, which compiles and appears to work correctly, but when it comes to the receiving code, I'm hitting a brick wall and can't seem to write the correct code.
Here is the code for the sending script (based on Heltec example):

// Turns the 'PRG' button into the power button, long press is off 
#define HELTEC_POWER_BUTTON   // must be before "#include <heltec_unofficial.h>"
#include <heltec_unofficial.h>

// Pause between transmitted packets in seconds. Set to zero to transmit only when pressing the user button.
#define PAUSE               60

// Frequency in MHz. Check your regulations for what is legal in your area.
#define FREQUENCY           866.3       // for Europe

// LoRa bandwidth.
#define BANDWIDTH           250.0

// Spreading factor from 5 to 12.
#define SPREADING_FACTOR    9

// Transmit power in dBm. 14dBm for 25mW.
#define TRANSMIT_POWER      1

long counter = 0;
uint64_t last_tx = 0;
uint64_t tx_time;
uint64_t minimum_pause;

typedef struct struct_message1 {
    float temp = 20;
    float temp_gnd = 18;
    float humid = 78;
    float humid_gnd = 85;
    float SL_press = 1021;
    float radValue = 300;
    float rain = 0;
    float kph = 0;
    float kphGust = 0;
    float rainCumul = 0.32;
    float solP1 = 560;
    float solP2 = 675;
    float battShI1 = -0.34;
    float battShI2 = -0.62;
    float battV1 = 4.02;
    float battV2 = 4.01;
    float loadP1 = 162;
    float loadP2 = 132;
    float rssiWifi = -98.2;
} struct_message1;

// Create a struct_message called wx_data
struct_message1 wx_data1;

void setup() {
  heltec_setup();
  Serial.println("TX  Radio init");
  RADIOLIB_OR_HALT(radio.begin());

  display.displayOff();
  
  // Set radio parameters
//  both.printf("Frequency: %.2f MHz\n", FREQUENCY);
  RADIOLIB_OR_HALT(radio.setFrequency(FREQUENCY));
  
//  both.printf("Bandwidth: %.1f kHz\n", BANDWIDTH);
  RADIOLIB_OR_HALT(radio.setBandwidth(BANDWIDTH));
  
//  both.printf("Spreading Factor: %i\n", SPREADING_FACTOR);
  RADIOLIB_OR_HALT(radio.setSpreadingFactor(SPREADING_FACTOR));
  
//  both.printf("TX power: %i dBm\n", TRANSMIT_POWER);
  RADIOLIB_OR_HALT(radio.setOutputPower(TRANSMIT_POWER));
}

void loop() {
  heltec_loop();

  bool tx_legal = millis() > last_tx + minimum_pause;

  // Transmit a packet every PAUSE seconds or when the button is pressed
  if ((PAUSE && tx_legal && millis() - last_tx > (PAUSE * 1000)) || button.isSingleClick()) {
    if (!tx_legal) {
  //    both.printf("Legal limit, wait %i sec.\n", (int)((minimum_pause - (millis() - last_tx)) / 1000) + 1);
      return;
    }


  //  both.printf("TX [%s] ", String(counter).c_str());
    heltec_led(50); // 50% brightness is plenty for this LED
    tx_time = millis();
    Serial.print(counter);
    RADIOLIB(radio.transmit((uint8_t *)&wx_data1, sizeof wx_data1)); 

    tx_time = millis() - tx_time;
    heltec_led(0);

    if (_radiolib_status == RADIOLIB_ERR_NONE) {
  Serial.printf("OK (%i ms)\n", (int)tx_time);
    } else {
  //    both.printf("fail (%i)\n", _radiolib_status);
    }

    // Maximum 1% duty cycle
    minimum_pause = tx_time * 100;
    last_tx = millis();
  }
}

My coding is probably ugly, but it seems to work.
Could one of you help me with a code using this library which would be able to read this structure data packet?
Thanks a million!
Guy

If you can tell us what it is you want to do, it is very likely the code exists. I have a few Heltec boards and have yet to write any code, everything I needed was in the samples. HOWEVER, finding and navigating the Heltec code base is a challenge to say the least. I think it has improved, but I haven't looked in a while.
Tell us what you want to do without suggesting a solution, and tell us the board model, etc, in fact, post pictures of the board front and back. I assume you have two identical boards.

not used the heltec_unofficial library
I have used the SX12XX-LoRa library to transmit a structure P2P between a Heltec LoRa V2 and a Heltec LoRa V3 (and a Adafruit Feather 32u4 LoRa))

@guy9ak I forgot to mention that, unofficial is asking for trouble, and the Heltec boards are now in the esp32 boards. LOTS of Heltec boards.


Hi. Thanks for your quick response.
The board is a Heltec LoRa 32 v3.2. They're about identical to the v3.1, except for a couple of changes on the circuitboard which involves the power system, if I understand it right.
If you look at my code for the sending side (the weather station), it has a structure "wx_data1" which I am trying to send to the receiver unit (so point to point) at my house about 3km away (I tested the link, it works fine).
That is where I am. I can't get a receiving code to work to get that structure.
Thanks.


Hi Horace.
This looks very promising (I've looked at the "LoRa_Structure_RX.ino" quickly, and it looks like that is exactly what I am trying to do. Now, I hope to get it to compile.
Thanks.

Avoid where possible mixing libraries, it can be very problematic.

If your using "LoRa_Structure_RX.ino" for the RX then use that libraries matching "LoRa_Structure_TX.ino" for the TX.

3km???? I can only get maybe 200 metres.

It's complaining about "LED1" not being defined. Do you know what is it supposed to be defined as?

Yes, I live in the country-side and it's line-of-sight. Using just the little stubby antenna that comes with the Heltec board, I get about -90dBm to -95dBm. Works great.

what code is complaining? upload the code?

I can compile and link the following examples OK
File>Examples>SX12XXLT LoRa Library>SX126x_examples>Basics>15_LoRa_Structure_RX
File>Examples>SX12XXLT LoRa Library>SX126x_examples>Basics>14_LoRa_Structure_TX

Tools>Board set to "Heltec WiFi LoRa 32(V3)"

1 Like

Then your likely not copying the example correctly.

LED1 is defined in the 'Settings.h' file that is included with the '15_LoRa_Structure_RX.ino' file.

So if LED1 is reporting as not defined, did you edit the 15_LoRa_Structure_RX.ino to not include the 'Settings.h' file or edit 'Settings.h' to exclude the LED1 pin definition ?

1 Like

Hi,
I don't know how to reply to two people at the same time, so this is in response to @srnet also.

Here is the code that I tried to compile. I essentially used the raw copy button from the example, so I don't know how it would have missed something, but for the sake of the argument, here is the code the way it is in my Arduino IDE:

/*******************************************************************************************************
  Programs for Arduino - Copyright of the author Stuart Robinson - 17/12/19

  This program is supplied as is, it is up to the user of the program to decide if the program is
  suitable for the intended purpose and free from errors.
*******************************************************************************************************/

/*******************************************************************************************************
  Program Operation - This program demonstrates the receiving of a structure as a LoRa packet. The packet
  sent is typical of what might be sent from a GPS tracker.

  The structure type is defined as trackerPacket and an instance called location1 is created. The structure
  includes a character array (text).

  The matching receiving program is '15_LoRa_RX_Structure' can be used to receive and display the packet,
  though the program '9_LoRa_LowMemory_RX' should receive it as well, since the packet contents are the same.

  Not that the structure definition and variable order (including the buffer size) used in the transmitter
  need to match those used in the receiver. Good luck.

  The contents of the packet received, and printed to serial monitor, should be;

  "tracker1"     (buffer)      - trackerID
  1+             (uint32_t)    - packet count
  51.23456       (float)       - latitude
  -3.12345       (float)       - longitude
  199            (uint16_t)    - altitude
  8              (uint8_t)     - number of satellites
  3999           (uint16_t)    - battery voltage
  -9             (int8_t)      - temperature

  Serial monitor baud rate is set at 9600.

*******************************************************************************************************/

#include <SPI.h>
#include <SX126XLT.h>
#include "Settings.h"

SX126XLT LT;

uint8_t RXPacketL;               //stores length of packet received
uint32_t RXpacketCount;          //count of received packets
int8_t PacketRSSI;               //RSSI of received packet
int8_t PacketSNR;                //signal to noise ratio of received packet
uint32_t errors;                 //count of packet errors


struct trackerPacket
{
  uint8_t trackerID[13];
  uint32_t txcount;
  float latitude;
  float longitude;
  uint16_t altitude;
  uint8_t satellites;
  uint16_t voltage;
  int8_t temperature;
};

struct trackerPacket location1;                 //define an instance called location1 of the structure trackerPacket


void loop()
{
  RXPacketL = LT.receive( (uint8_t *) &location1, sizeof(location1), 0, WAIT_RX); //wait for a packet to arrive with no timeout

//  digitalWrite(LED1, HIGH);                     //something has happened, what I wonder ?

  PacketRSSI = LT.readPacketRSSI();
  PacketSNR = LT.readPacketSNR();

  if (RXPacketL == 0)
  {
    packet_is_Error();
  }
  else
  {
    packet_is_OK();
  }

  digitalWrite(LED1, LOW);
  Serial.println();
}


void printlocation1()
{
  uint8_t buff[13];                                    //define a buffer to receive a copy from the structure
  memcpy (&buff, &location1.trackerID, sizeof(buff));  //copy the contents of buffer in struture to buff[]

  //now print the contents of the structure
  Serial.print((char*) buff);                          //cast to a char type for printing
  Serial.print(F(","));
  Serial.print(location1.txcount);
  Serial.print(F(","));
  Serial.print(location1.latitude, 5);
  Serial.print(F(","));
  Serial.print(location1.longitude, 5);
  Serial.print(F(","));
  Serial.print(location1.altitude);
  Serial.print(F("m,"));
  Serial.print(location1.satellites);
  Serial.print(F("sats,"));
  Serial.print(location1.voltage);
  Serial.print(F("mV,"));
  Serial.print(location1.temperature);
  Serial.print(F("c "));
}


void packet_is_OK()
{
  RXpacketCount++;
  Serial.print(RXpacketCount);
  Serial.print(F("  "));
  printlocation1();
  printpacketDetails();
}


void packet_is_Error()
{
  uint16_t IRQStatus;
  IRQStatus = LT.readIrqStatus();

  if (IRQStatus & IRQ_RX_TIMEOUT)
  {
    Serial.print(F("RXTimeout"));
  }
  else
  {
    errors++;
    Serial.print(F("PacketError"));
    printpacketDetails();
    Serial.print(F("IRQreg,"));
    Serial.print(IRQStatus, HEX);
  }
}

void printpacketDetails()
{
  Serial.print(F("  RSSI,"));
  Serial.print(PacketRSSI);
  Serial.print(F("dBm,SNR,"));
  Serial.print(PacketSNR);
  Serial.print(F("dB"));
}


void led_Flash(uint16_t flashes, uint16_t delaymS)
{
  uint16_t index;

  for (index = 1; index <= flashes; index++)
  {
    digitalWrite(LED1, HIGH);
    delay(delaymS);
    digitalWrite(LED1, LOW);
    delay(delaymS);
  }
}


void setup(void)
{
  pinMode(LED1, OUTPUT);                        //setup pin as output for indicator LED
  led_Flash(2, 125);                            //two quick LED flashes to indicate program start

  Serial.begin(9600);

  SPI.begin();

  if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
  {
    led_Flash(2, 125);
    delay(1000);
  }
  else
  {
    Serial.println(F("Device error"));
    while (1)
    {
      led_Flash(50, 50);
    }
  }

  LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate, Optimisation);

  Serial.print(F("Receiver ready"));
  Serial.println();
  Serial.println();
}

And here are the errors I get:

"C:\Users\gctyt\AppData\Local\Temp.arduinoIDE-unsaved2025318-20576-1avoo66.m43w\sketch_apr18a\sketch_apr18a.ino: In function 'void loop()':
C:\Users\gctyt\AppData\Local\Temp.arduinoIDE-unsaved2025318-20576-1avoo66.m43w\sketch_apr18a\sketch_apr18a.ino:68:16: error: 'LED1' was not declared in this scope; did you mean 'LED'?
68 | digitalWrite(LED1, HIGH); //something has happened, what I wonder ?
| ^~~~
| LED
C:\Users\gctyt\AppData\Local\Temp.arduinoIDE-unsaved2025318-20576-1avoo66.m43w\sketch_apr18a\sketch_apr18a.ino: In function 'void led_Flash(uint16_t, uint16_t)':
C:\Users\gctyt\AppData\Local\Temp.arduinoIDE-unsaved2025318-20576-1avoo66.m43w\sketch_apr18a\sketch_apr18a.ino:157:18: error: 'LED1' was not declared in this scope; did you mean 'LED'?
157 | digitalWrite(LED1, HIGH);
| ^~~~
| LED
C:\Users\gctyt\AppData\Local\Temp.arduinoIDE-unsaved2025318-20576-1avoo66.m43w\sketch_apr18a\sketch_apr18a.ino: In function 'void setup()':
C:\Users\gctyt\AppData\Local\Temp.arduinoIDE-unsaved2025318-20576-1avoo66.m43w\sketch_apr18a\sketch_apr18a.ino:167:11: error: 'LED1' was not declared in this scope; did you mean 'LED'?
167 | pinMode(LED1, OUTPUT); //setup pin as output for indicator LED
| ^~~~
| LED
C:\Users\gctyt\AppData\Local\Temp.arduinoIDE-unsaved2025318-20576-1avoo66.m43w\sketch_apr18a\sketch_apr18a.ino:174:16: error: 'NSS' was not declared in this scope; did you mean 'SS'?
174 | if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
| ^~~
| SS
C:\Users\gctyt\AppData\Local\Temp.arduinoIDE-unsaved2025318-20576-1avoo66.m43w\sketch_apr18a\sketch_apr18a.ino:174:21: error: 'NRESET' was not declared in this scope; did you mean 'ENETRESET'?
174 | if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
| ^~~~~~
| ENETRESET
C:\Users\gctyt\AppData\Local\Temp.arduinoIDE-unsaved2025318-20576-1avoo66.m43w\sketch_apr18a\sketch_apr18a.ino:174:29: error: 'RFBUSY' was not declared in this scope; did you mean 'BUSY'?
174 | if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
| ^~~~~~
| BUSY
C:\Users\gctyt\AppData\Local\Temp.arduinoIDE-unsaved2025318-20576-1avoo66.m43w\sketch_apr18a\sketch_apr18a.ino:174:37: error: 'DIO1' was not declared in this scope; did you mean 'DIO0'?
174 | if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
| ^~~~
| DIO0
C:\Users\gctyt\AppData\Local\Temp.arduinoIDE-unsaved2025318-20576-1avoo66.m43w\sketch_apr18a\sketch_apr18a.ino:174:43: error: 'LORA_DEVICE' was not declared in this scope
174 | if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
| ^~~~~~~~~~~
C:\Users\gctyt\AppData\Local\Temp.arduinoIDE-unsaved2025318-20576-1avoo66.m43w\sketch_apr18a\sketch_apr18a.ino:188:16: error: 'Frequency' was not declared in this scope
188 | LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate, Optimisation);
| ^~~~~~~~~
C:\Users\gctyt\AppData\Local\Temp.arduinoIDE-unsaved2025318-20576-1avoo66.m43w\sketch_apr18a\sketch_apr18a.ino:188:27: error: 'Offset' was not declared in this scope
188 | LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate, Optimisation);
| ^~~~~~
C:\Users\gctyt\AppData\Local\Temp.arduinoIDE-unsaved2025318-20576-1avoo66.m43w\sketch_apr18a\sketch_apr18a.ino:188:35: error: 'SpreadingFactor' was not declared in this scope
188 | LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate, Optimisation);
| ^~~~~~~~~~~~~~~
C:\Users\gctyt\AppData\Local\Temp.arduinoIDE-unsaved2025318-20576-1avoo66.m43w\sketch_apr18a\sketch_apr18a.ino:188:52: error: 'Bandwidth' was not declared in this scope
188 | LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate, Optimisation);
| ^~~~~~~~~
C:\Users\gctyt\AppData\Local\Temp.arduinoIDE-unsaved2025318-20576-1avoo66.m43w\sketch_apr18a\sketch_apr18a.ino:188:63: error: 'CodeRate' was not declared in this scope
188 | LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate, Optimisation);
| ^~~~~~~~
C:\Users\gctyt\AppData\Local\Temp.arduinoIDE-unsaved2025318-20576-1avoo66.m43w\sketch_apr18a\sketch_apr18a.ino:188:73: error: 'Optimisation' was not declared in this scope
188 | LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate, Optimisation);
| ^~~~~~~~~~~~
exit status 1

Compilation error: 'LED1' was not declared in this scope; did you mean 'LED'?"

I am obviously missing something. To install the sx12xx library, I followed the instructions from the ReadMe.md file.

Yes you are.

You may have copied the sketch, tosketch_apr18a.ino, but it looks like the required Settings.h file is empty, since not only is the LED1 definition missing, all the others are too, hence the large number of errors about missing definitions.

Check the original Settings.h file for the sketch in the library.

as @srnet stated in post 12
LED1 is defined in the 'Settings.h' file that is included with the '15_LoRa_Structure_RX.ino' file.

the directory which contains file 15_LoRa_Structure_RX.ino should also contain Settings.h, e.g.

the Arduino IDE such have two tabs 15_LoRa_Structure_RX.ino and Settings.h

as you see LED1 is defined in Settings.h

1 Like

PUT ALL CODE AND ERROR LOGS IN CODE TAGS.
What raw code button? The sample code is in the IDE, and you just click it. If you want to change the sample you will need to do a 'save as'
Here is both the sample transmitter and receiver, all on one screen.
Your code seems more complex, why?

Right now, I'm trying the SX12XX-LoRa library, that's why it is different from the code you are talking about. Your code sends a string, not a structure. There are a lot of examples to send and receive strings, but very few sending and receiving structure variable.
Also, the button I am talking about is in the top right corner of the example code in Git repository where the SX12XX library is.
Sorry about the confusion. I am trying to find an example that compile and works.
Thanks.

A structure is still a string; just use a string pointer and set it to the structure. If you insist on using non-official libraries, then expect to have problems. Lora is quite simple, so I will say goodbye.

To you and @srnet:
Ok, this is where my lack of experience with this whole Arduino IDE coding adventure shows.
When I installed the library, I was assuming that it would install the *.h files as well, but apparently, from what you are saying, I have to add it to the code? Do I have to do that with all *.h files?
Ok, so I tried that and, of course, it's working.
Could you explain me why I have to do this in this case, because in other sketches that had to include *.h files I did not add a tab with the *.h files and it compiled fine. What's the difference with this example?
Thanks for all you guy's help and putting up with my ignorance.

I am confused. On one of your first reply to my post, you said that using the heltec_unofficial library was asking for trouble, so per your advice I am looking at alternative, so I don't understand your reaction. Sorry.