3
votes

I'm trying to transmit from one ESP32 LoRa node to another one in low-power mode and in compliance with european regulations.

ESP32 board: TTGO LoRa32 OLED Board V1.0 (here and here).


Below the LoRa sender sketch I wrote:
/*
 * LoRa (low-power) sender for IoT projects
 *  
 * Tested on a TTGO LoRa32 OLED Board V1.0 
 * 
 * Based on the LoRa examples and the board 
 * documentation
 * 
 * More on the deep sleep with timer wake up: 
 *  
 *    Examples > ESP32 > Deep Sleep > TimerWakeUp sketch
 *    
 *    
 * ERC Recommendation
 * h1.4 frequency band requires <= 1% duty cycle and 25mW (14 db) maximum power
 * => 36 seconds every hour (so: 1 sec transmitting, 99 secs idle) 
 * 
 * 
 * Created 11 June 2019
 * by DP 
 *    
 */
 
#include <SPI.h>   // allows communication with SPI devices 
#include <LoRa.h>
#include <SSD1306.h>   // provides API to work with OLED displays

// defines the pins used by the transceiver module
#define SS 18   // GPIO18 - SX1278's CS   - LoRa radio chip select
#define RST 14   // GPIO14 - SX1278's RESET   - LoRa radio reset
#define DI0 26   // GPIO26 - SX1278's IRQ   - IRQ pin

#define BAND 868E6   // EU   - Italy

// deep sleep 
#define uS_TO_S_FACTOR 1000000  // conversion factor for micro seconds to seconds 
#define TIME_TO_SLEEP  5        // time ESP32 will go to sleep (in seconds)   - 99 for (about) 1% duty cycle  


// an object of class SSD1306 
// first parameter: the I2C address of the display
// second parameter: the number of the SDA
// third parameter: the SCL pin
SSD1306 display(0x3c, 4, 15);

// stores the data on the RTC memory so that it will not be deleted during the deep sleep
RTC_DATA_ATTR int bootCount = 0; 
RTC_DATA_ATTR int pckCounter = 0;   // sending packet number...

 
void setup() {   
  Serial.begin(115200);   // initializes serial data transmission  
  while(!Serial);   // waits for serial port to connect 

  Serial.println("LoRa low-power Sender");
  
  pinMode(16, OUTPUT);
  digitalWrite(16, LOW);   // sets GPIO16 low to reset the OLED
  delay(50);
  digitalWrite(16, HIGH);   // while the OLED is running, GPIO16 must go to high  
  pinMode(2, OUTPUT);
  digitalWrite(2, LOW);   // sets the onboard LED low 
  
  // LoRa transceiver module setup 
  LoRa.setPins(SS, RST, DI0);   // overrides the default CS, reset, and IRQ pins used by the library

  // initializes the transceiver module with a specified frequency
  while (!LoRa.begin(BAND)) {   // LoRa.begin returns 1 on success, 0 on failure
    Serial.println(".");
  }

  // changes the spreading factor to 12 -> slower speed but better noise immunity
  LoRa.setSpreadingFactor(12);   // ranges from 6-12, default is 7 

  // changes the sync word (0xF3) to match the receiver
  // the sync word assures you don't get LoRa messages from other LoRa transceivers  
  LoRa.setSyncWord(0xF3);   // ranges from 0-0xFF     
 
  // LoRa.setTxPower(txPower);   // defaults to 17

  // initializes the display by calling the init method of the display object 
  display.init();   // receives no arguments and returns void

  // display.flipScreenVertically();   // LCD is broken!
  display.setFont(ArialMT_Plain_16);   // sets the current font
  display.drawString(0, 0, "Initialization");   // x, y, message to show
  display.drawString(0, 16, "completed");
  display.display();
  delay(1500);   // small delay so that the user can read it  

  Serial.println("LoRa init completed");    

  //Increments boot number and prints it every reboot
  bootCount++;
  Serial.println("Boot number: " + String(bootCount));

  sendData();   // sends the data...

  // deep sleep
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) + " Seconds");
  Serial.println("Going to sleep now");
  Serial.flush();   // waits for the transmission of outgoing serial data to complete 
  esp_deep_sleep_start();   // enters deep sleep with the configured wakeup options
}

void loop(){
  // this is not going to be called
}

// sends the data to the receiver
void sendData() {
  
  Serial.print("Sending packet: ");
  Serial.println(pckCounter);

  display.clear();   // clears the display
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.drawString(0, 0, "Sending ");
  display.drawString(0, 16, "packet: " + String(pckCounter, DEC));
  display.display();
  
  digitalWrite(2, HIGH);   // LED is ON during transmission

  // sends the LoRa packet to the receiver
  LoRa.beginPacket();
  LoRa.print("hello ");
  LoRa.print(pckCounter);
  LoRa.endPacket();
  
  digitalWrite(2, LOW);   // turns the LED off after transmission

  pckCounter++;
}

The sketch runs without errors (the code on the shop's page contains some errors, so I encourage you to use this one just to play with it). My questions:

  • I forgot to initialize the SPI communication:

    SPI.begin (SCK, MISO, MOSI, SS);

    But nevertheless, it worked anyway. I didn't expect it. My first question is: what am I missing?

  • I live in Europe. ERC Recommendation document says that h1.4 frequency band (I'm transmitting at 868 Mhz) requires <=1% duty cycle and 25mW (14db) maximum power. This means that I can transmit for 36 seconds every hour (let's say that I transmit for 1 sec and then the ESP32 'sleeps' for 99 seconds). I can achieve that writing (it's not the more accurate way but it should work):

    #define TIME_TO_SLEEP 99

    What about the erp? Let's say that the antenna has a 2db gain, so I can set the transmission power to 12db (12db + 2db -> 14db, great. It's ok!):

    LoRa.setTxPower(12);

  • My second question: am I right (about both settings)? Am I missing something?

  • Last question: please, feel free to give me any (if you have) feedback/suggestion to improve this sketch!

3

3 Answers

4
votes

That looks good, have you tested the power consumption during deep sleep? I've got the same board (TTGO ESP32 LORA with the OLED), and get about 38-50mA when awake, and 10mA during sleep. You can try LoRa.end() and LoRa.sleep() after you've finished sending to send the chip to sleep, but I'm not sure how much power this saves.

There are some discussions going on here about further ways to drop the power, but I've not been able to get it below 10mA for the TTGO.

1
votes

In general, I have bad experience with LilyGo products and low current. I tested several of them (not the LoRa one) and usually they draw 1mA at minimum. I think the truly powersaving sensor can be made from Atmel LoRa node like this.

Added: Just for your information, I have testing rig (868MHz LoRa Radio Node V1.0) that sends LoRa message every hour and it is running for months on battery. Now after more than 3 months the battery drop is about 0.25V.

0
votes

Very nice, looks very similar to my sketch. I think the battery connector is using a low-drop regulator but this will still consume milliamps. As I am currently evaluating an testing alternatives: Did you ever try to directly power the board with the GND/3V3 connectors? Using a standard 3.7V LiPo battery and some suitable Schottky diode to generate a voltage drop of about 0.2V should work fine to stay below 3.6V even with a full battery.