Ever wanted to monitor your front door, garden gate, or barn from over 13 miles (20 kilometers) away without using Wi-Fi, cellular networks, or paying a monthly fee? In this video, I’ll show you exactly how to do that using the powerful LoRa (Long Range Radio) technology and the Heltec WiFi LoRa 32 module inside the compact Meshnology N32 case. This is the perfect project for farms, cabins, remote properties, or any off-grid application.
Watch as I build and demonstrate a fully functional remote door monitoring system using a Hall sensor and relay control — all transmitted wirelessly using LoRa. With no dependency on the internet or SIM cards, this project is ideal for DIY enthusiasts, preppers, and makers who want reliable long-range monitoring and control solutions.
Project of this video:
Transmitter code: Simple ON/OFF (this code)
Transmitter code: Relay Toggle
Receiver Code: display the relay state, turn ON relay or buzzer
Topics in this lesson
Use Chapters from timeline or click on the time
00:00 Start
1:58 Project explained
6:41 N32 Case package
12:18 Wiring explained
18:41 Hall sensor sensitivity adjustment
23:16 Installing Library on Arduino IDE
27:37 Code: Transmitter (TX)
30:18 Code: Receiver (RX)
31:52 Demo: on in lab
32:59 Demo: On the door
33:55 Demo: Range on the field
Trannsmitter Code to turn ON/OFF a relay over LoRa band
/*
File: Door_Alarm_TX.ino
Written on May 16, 2025
written for www.NyBot.cc www.robojax.com
This is door alarm transmitter sketch
this sktech transmitts secure ON/OFF signal using Heltec WiFi LoRa 32
and also it displays OPEN or CLOSED on the OLED.
Watch full video explaination: https://youtu.be/-YWocAllrbA
this code has been part of Robojax_HeltecLoRa32 library
and can be downloaded from robojax.com
*/
#include
#include
#include "LoRaWan_APP.h"
#include
bool debug = false;
#define HALL_SWITCH_PIN 4 //the pin connected a push button
#define BATTERY_PIN 1 //do not change
#define ADC_CTRL_PIN 37 //do not change
const char *displayTexttitle = "Door:"; //shown on the screen
const char *displayTexTX = "(TX)"; //shown on the screen
const char *displayTexRelayON = "OPEN"; //shown on the screen
const char *displayTexRelayOFF = "CLOSED"; //shown on the screen
mbedtls_aes_context aes;
const char *userKey = "6tfDs$wEq3!"; //Security key (change it).
SSD1306Wire oledDisplay(0x3c, 500000, SDA_OLED, SCL_OLED, GEOMETRY_128_64, RST_OLED);
Robojax_HeltecLoRa32 robojaxDisplay(&oledDisplay);
bool relayState;
int lastButtonState = LOW; //because of PULLDOWN
String displayTextStateValue= displayTexRelayOFF;
volatile bool doorOpened = false; // Flag set by interrupt
unsigned long lastInterruptTime = 0;
const unsigned long debounceDelay = 50; // 50ms debounce time
#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 IRAM_ATTR handleButtonInterrupt();
void readDoorSensor() ;
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(HALL_SWITCH_PIN, INPUT);//pin for hall switch
attachInterrupt(digitalPinToInterrupt(HALL_SWITCH_PIN), handleButtonInterrupt, CHANGE);
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 GPIO4
readDoorSensor();
if(debug)
{
Serial.print(displayTexttitle);Serial.print(":");
Serial.println(displayTextStateValue);
}
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(displayTextStateValue, 0, 30, 24, true);//size 24 font
//now send the value
robojaxDisplay.sendStringSecure(displayTextStateValue);
delay(100);
}
// Interrupt service routine
void IRAM_ATTR handleButtonInterrupt() {
unsigned long interruptTime = millis();
if (interruptTime - lastInterruptTime > debounceDelay) {
doorOpened = true;
}
lastInterruptTime = interruptTime;
}
void readDoorSensor() {
if (doorOpened) {
doorOpened = false; // Reset flag
int currentButtonState = digitalRead(HALL_SWITCH_PIN);
if(debug)
{
Serial.print("Door state: ");
Serial.println(currentButtonState);
}
// if door open ==HIGH
if (currentButtonState == HIGH) {
displayTextStateValue = displayTexRelayON ;
if(debug)
{
Serial.print("State updated: ");
Serial.println(displayTextStateValue);
}
}else{
displayTextStateValue = displayTexRelayOFF;
}
}
}//readDoorSensor() end
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;
}