All Projects
Open Source StructureSense · 2026 C++ · PlatformIO · ESP32 GitHub

LoraManager2
LoRaWAN Class C for ESP32 + SX1262

An open-source Arduino/PlatformIO library that solved a problem no existing Heltec library could: true Class C LoRaWAN capability — enabling near-real-time downlinks for industrial actuator control.

Role
Sole Author
Timeline
~3 Months
Target Hardware
Heltec WiFi
LoRa 32 V3
License
MIT · Open Source

The Problem

45 seconds is not real-time.

The LoRa DMX project needed to control DMX512 stage lighting over LoRaWAN. For that to work, downlinks — commands sent from the cloud back to a device — needed to arrive fast. Not "fast enough for a slow sensor." Fast enough to control a relay or trigger a light cue.

Every existing library for the Heltec WiFi LoRa 32 V3 operated in LoRaWAN Class A: the device only listens for downlinks immediately after it sends an uplink. Between uplinks, it's deaf. In practice, that meant waiting up to 45 seconds to see a state change after sending a command.

Class C devices listen continuously. No uplink required. Commands arrive in under 5 seconds. The problem was: no library exposed true Class C on Heltec chips.

The same limitation applied to relay-based access control — a door lock or garage controller can't wait 45 seconds. Real actuator control requires real-time. That meant building the library from scratch.

The Breakthrough

Finding the one library that could do it.

The SX1262 radio chip is powerful — it's fully capable of Class C operation. The issue was every popular Arduino wrapper abstracted it away. After three months of digging, the key was an obscure library by beegee-tokyo: SX126x-Arduino. It exposed the low-level LoRaWAN stack that made Class C achievable.

This was also pre-peak AI codegen for embedded C++. Most tools couldn't navigate the SX126x LoRaWAN stack, regional sub-band configuration, or the OTAA handshake edge cases. It required reading datasheets, tracing register writes, and a lot of failed join attempts before the first Class C downlink arrived in under 5 seconds.

Class A vs Class C
45s
Class A worst case
<5s
Class C typical

Same hardware. Same network. Different LoRaWAN class.

Key dependency
beegee-tokyo/SX126x-Arduino

The only library with a complete enough LoRaWAN stack to support Class C mode on the SX1262.

Architecture

Event-driven. Runtime-configured.

LoraManager2 wraps the SX126x-Arduino stack in a clean API centered on two config structs and a set of lambda callbacks. Nothing is hardcoded — credentials, region, sub-band, data rate, and pin mappings are all passed at runtime, making the library portable across boards and deployments.

Downlink commands arrive as JSON payloads, parsed by ArduinoJson and dispatched to registered callbacks. The application layer never touches the radio — it just responds to events like onCommand() or onClassChanged().

Data Flow
flowchart TD A["Application Code"] B["LoraManager2\nbegin() + loop()"] C["SX126x-Arduino\nLoRaWAN Stack"] D["SX1262 Radio\n(Heltec V3)"] E["LoRaWAN Network\n(TTN / ChirpStack)"] F["onCommand()\nCallback"] G["Actuator Logic\n(DMX / Relay)"] A -->|"LoraConfig\nHardwareConfig"| B B -->|"OTAA Join\nClass C init"| C C -->|"SPI"| D D -->|"915MHz RF"| E E -->|"Downlink JSON"| D D -->|"IRQ"| C C -->|"Parsed payload"| B B -->|"Dispatch"| F F --> G style A fill:#1e293b,color:#94a3b8,stroke:#334155 style B fill:#1e293b,color:#6ee7b7,stroke:#059669 style C fill:#1e293b,color:#94a3b8,stroke:#334155 style D fill:#1e293b,color:#94a3b8,stroke:#334155 style E fill:#1e293b,color:#6CCCDF,stroke:#2a97ae style F fill:#1e293b,color:#6ee7b7,stroke:#059669 style G fill:#1e293b,color:#f59e0b,stroke:#d97706

API

The surface area is small on purpose.

Lifecycle
begin(LoraConfig, HardwareConfig)

Initialize the stack, OTAA join, switch to Class C

loop()

Must be called in main loop — handles radio events

Transmission
send(payload)

Unconfirmed uplink

sendConfirmed(payload)

Acknowledged uplink — waits for ACK

Status
isJoined()

Network connection state

getCurrentClass()

Returns active LoRaWAN class (A/B/C)

getDeviceEUI()

Device EUI for TTN registration

Event Callbacks
onJoined(fn)

Fires when OTAA join succeeds

onDownlink(fn)

Raw downlink received

onCommand(fn)

JSON command parsed and dispatched

onClassChanged(fn)

Class switch confirmed by network

Built For

Two projects. Both needed it to work.

LoRa DMX — Stage Lighting Control

Controlling DMX512 lighting fixtures over LoRaWAN required sub-second-class responsiveness. Class A's 45-second window made live lighting effects impossible. LoraManager2 made the LoRa DMX project viable.

View LoRa DMX project →
Relay-Based Access Control

Controlling door locks and garage relays over LoRaWAN. The Dragino LT-22222-L relay needed to respond to a cloud trigger in seconds, not minutes. The same Class C architecture that powered LoRa DMX drove access control commands.

Tech Stack

Library

C++PlatformIOArduino FrameworkLoRaWAN Class COTAAJSON Downlinks

Hardware & Dependencies

ESP32-S3SX1262Heltec WiFi LoRa 32 V3beegee-tokyo/SX126x-ArduinoArduinoJsonArduino Ticker