In this groundbreaking video, we demonstrate how to wirelessly transmit voltage readings up to 150V over a staggering 13-mile (20km) distance using the Heltec WiFi LoRa 32 V3 module and the Meshnology N32 case with a 3000mAh battery and high-gain antenna. This real-world test proves LoRa’s incredible long-range capabilities—perfect for remote monitoring of solar panels, batteries, or industrial sensors without WiFi or cellular networks!
The code below is to read DC voltage of up to 150V using the two resistor of volage divider and transmit the voltage over LoRa band securely.
Project of this video
Secure Transmitter code for sendign Voltage (this code)
Secure Receiver Code for receiving volage
Topics in this lesson
Use Chapters from timeline or click on the time
00:00 Start
3:33 Introduction to the board and LoRa
5:47 N32 Case for WiFi LoRa 32
12:26 Voltage divider to measure up to 150V
19:47 Preparing wire to measure voltage
20:41 Installing library for WiFi LoRa 32
25:02 Transmission Code explained
27:16 Receiver Code explained
28:36 Demonstration of reading voltage
31:39 Real world distance range test (13 mile)
Transmitter code to send secure Voltage over LoRa band
/*
This is Arduino Code to measure DC voltage up to 150V using Heltel WiFi LoRa 32 V3 and send it to over 20km or 13 miles
Watch the full video details https://youtu.be/rOVVl9EI-So
You will need to download the zip library (Robojax_HeltecLoRa32) from Robojax.com
See the resouces page here: https://robojax.com/course1/?vid=lecture117
R1 >> R2 because R2 must divide voltage to about 3V. and major voltage should drop on R1.
Battery (+)<----
|
[R1]
|
|------------>GPIO-7
|
[R2] to ESP32-->
|
GND (-) <-------------- ---->GND
TEXT_ALIGN_LEFT 0
TEXT_ALIGN_CENTER 1
TEXT_ALIGN_RIGHT 2
*/
#include
#include
#include "LoRaWan_APP.h"
#include
bool debug = false;
#define VOLTAGE_READING_PIN 4 //the pin voltage you are reading from
const int R1 = 39120;//in home. this is 39120 ohm
const int R2 = 3312;//we read the voltage acrosst this resistor
float voltage;
const float CALIB_FACTOR = 1.007f; // Your calibration factor. 1.0 means do not callibrate
#define BATTERY_PIN 1 //do not change
#define ADC_CTRL_PIN 37 //do not change
const char *displayTexttitle = "Voltage:"; //shown on the screen
const char *displayTexTX = "(TX)"; //shown on the screen
mbedtls_aes_context aes;
const char *userKey = "hyhT676#h~_876s"; //Security key.
SSD1306Wire oledDisplay(0x3c, 500000, SDA_OLED, SCL_OLED, GEOMETRY_128_64, RST_OLED);
Robojax_HeltecLoRa32 robojaxDisplay(&oledDisplay);
#define RF_FREQUENCY 915000000 // Hz
#define TX_OUTPUT_POWER 2 // dBm from 2 to 20. when powered via battery 2 to 14dBm
#define LORA_BANDWIDTH 0 // [0: 125 kHz,
// 1: 250 kHz,
// 2: 500 kHz,
// 3: Reserved]
#define LORA_SPREADING_FACTOR 7 // [SF7..SF12]
#define LORA_CODINGRATE 1 // [1: 4/5,
// 2: 4/6,
// 3: 4/7,
// 4: 4/8]
#define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx
#define LORA_SYMBOL_TIMEOUT 0 // Symbols
#define LORA_FIX_LENGTH_PAYLOAD_ON false
#define LORA_IQ_INVERSION_ON false
#define RX_TIMEOUT_VALUE 1000
#define BUFFER_SIZE 30 // Define the payload size here
char txpacket[BUFFER_SIZE];
char rxpacket[BUFFER_SIZE];
bool lora_idle=true;
static RadioEvents_t RadioEvents;
void VextON() {
pinMode(Vext, OUTPUT);
digitalWrite(Vext, LOW);
}
void OnTxDone(void);
void OnTxTimeout(void);
void decryptAES(uint8_t *data, const char *key);
void encryptAES(uint8_t *data, const char *key);
void processKey(const char *userKey, uint8_t *processedKey, size_t keySize);
void setup() {
Serial.begin(115200);
VextON();
delay(100); // OLED power on delay
pinMode(ADC_CTRL_PIN, OUTPUT);
// Set ADC_Ctrl to HIGH to enable the ADC circuit.
digitalWrite(ADC_CTRL_PIN, HIGH);
robojaxDisplay.begin();
//robojaxDisplay.displayText("Hello", 0, 0, 16, TEXT_ALIGN_LEFT);
//delay(1000);
//LoRa stuff
Mcu.begin(HELTEC_BOARD,SLOW_CLK_TPYE);
RadioEvents.TxDone = OnTxDone;
RadioEvents.TxTimeout = OnTxTimeout;
Radio.Init( &RadioEvents );
Radio.SetChannel( RF_FREQUENCY );
Radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH,
LORA_SPREADING_FACTOR, LORA_CODINGRATE,
LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON,
true, 0, 0, LORA_IQ_INVERSION_ON, 3000 );
}
void loop() {
//read the voltage at GPIO7
voltage = CALIB_FACTOR * robojaxDisplay.readAnyVoltage(VOLTAGE_READING_PIN, R1, R2);
if(debug)
{
robojaxDisplay.maxVoltage(R1, R2);
Serial.print("Voltage (TX): ");
Serial.println(voltage);
}
//robojaxDisplay.calculatResistor(R2, 40);
//robojaxDisplay.displayCenteredText("Robojax!", 24, 24); // Y=24, font size 24
String stringVoltage = String(voltage);
robojaxDisplay.displayLineText(displayTexttitle, 0, 0, 24, false);//size 24 font
robojaxDisplay.displayText(displayTexTX, 127, 5, 10, TEXT_ALIGN_RIGHT);//display TX on the right side
robojaxDisplay.displayLineText(stringVoltage+"V", 0, 30, 24, true);//size 24 font
robojaxDisplay.sendStringSecure(stringVoltage);
//robojaxDisplay.sendString( stringVoltage);
//robojaxDisplay.displaySmallBattery(v);
delay(500);
//robojaxDisplay.displayLargeBattery(voltage, 2);
// delay(2000);
// robojaxDisplay.displayLargeBattery(v, 2);
// delay(2000);
}
void OnTxDone( void )
{
if(debug)
Serial.println("TX done......");
lora_idle = true;
}
void OnTxTimeout( void )
{
Radio.Sleep( );
if(debug)
Serial.println("TX Timeout......");
lora_idle = true;
}