EzLoRaWAN is an evolution of the TheThingsNetwork_esp32 library. Indeed TheThingsNetwork_esp32 does not support SX126X type chips. This library uses the BasicMAC library as a replacement for mcci-catena/arduino-lmic. The objective of this library is to simplify as much as possible the configuration, the connection, the sending and receiving of frames to a LoRaWan network.
The library is tested for EU868 frequency plan (SX1262 & SX1276 chips). TODO enhance and verify for other frenquency plans
Pin assignment and initialization is automatic for some boards (see list below). In this case an AUTOPIN
constant is declared.
the following boards are tested with AUTOPIN
:
- HELTEC WIRELESS STICK (SX1276)
- HELTEC WIRELESS STICK V3 (SX1262)
- HELTEC WIFI LORA 32 V1 (SX1276)
- HELTEC WIFI LORA 32 V2 (SX1276)
- HELTEC WIRELESS PAPER (SX1262)
- HELTEC WIRELESS TRACKER V1.1 (SX1262)
- TTGO TBEAM 1 (SX1276)
To add new board edit the file target-config.h
Without AUTOPIN (for example for generic cards) you must define the board type, the SPI and LoRa chip pins as follow :
- for SX1262
#define BRD_sx1262_radio 1
#define RADIO_SCLK_PIN CHANGE_ME // depends on the pinout of the card
#define RADIO_MISO_PIN CHANGE_ME
#define RADIO_MOSI_PIN CHANGE_ME
#define RADIO_TX_PIN LMIC_CONTROLLED_BY_DIO2
#define RADIO_RX_PIN LMIC_UNUSED_PIN
#define RADIO_CS_PIN CHANGE_ME
#define RADIO_DIO0_PIN LMIC_UNUSED_PIN
#define RADIO_DIO1_PIN CHANGE_ME
#define RADIO_DIO2_PIN LMIC_UNUSED_PIN
#define RADIO_BUSY_PIN CHANGE_ME
#define RADIO_RST_PIN CHANGE_ME
#define RADIO_TCXO_PIN LMIC_CONTROLLED_BY_DIO3
You can see an example for LILYGO T3S3 in board_config.h in the ttn-otaa example
- for SX1276
#define BRD_sx1276_radio 1
#define RADIO_SCLK_PIN CHANGE_ME // depends on the pinout of the card
#define RADIO_MISO_PIN CHANGE_ME
#define RADIO_MOSI_PIN CHANGE_ME
#define RADIO_CS_PIN CHANGE_ME
#define RADIO_DIO0_PIN CHANGE_ME
#define RADIO_DIO1_PIN CHANGE_ME
#define RADIO_DIO2_PIN CHANGE_ME
#define RADIO_RST_PIN CHANGE_ME
#define RADIO_BUSY_PIN LMIC_UNUSED_PIN
#define RADIO_TCXO_PIN LMIC_UNUSED_PIN
#define RADIO_TX_PIN LMIC_UNUSED_PIN
#define RADIO_RX_PIN LMIC_UNUSED_PIN
In the sketch declare a const
as follow:
const lmic_pinmap lmic_pins = {
.nss = RADIO_CS_PIN,
.tx = RADIO_TX_PIN,
.rx = RADIO_RX_PIN,
.rst = RADIO_RST_PIN,
.dio = {RADIO_DIO0_PIN , RADIO_DIO1_PIN, RADIO_DIO2_PIN},
.busy = RADIO_BUSY_PIN,
.tcxo = RADIO_TCXO_PIN,
};
In setup function add :
SPI.begin(RADIO_SCLK_PIN, RADIO_MISO_PIN, RADIO_MOSI_PIN);
then call de begin()
method. (See ttn-otaa.ino
with board-config.h
in ttn-otaa example for more details)
Include and instantiate the EzLoRaWAN class. The constructor initialize the library with the Streams it should communicate with.
#include <EzLoRaWAN.h>
EzLoRaWAN ttn;
Start the LoRaWAN stack. The LoRa chip type and the pinout (LoRa & SPI) must be declared before call this method. (see the above and the target-config.h file for more details)
void begin();
Gets the provisioned AppEUI. The AppEUI is set using provision()
or join()
.
size_t getAppEui(char *buffer, size_t size);
return AppEui as an array of char
String getAppEui();
return AppEui as String
Gets the provisioned DevEUI. The DevEUI is set using provision()
or join()
.
size_t getDevEui(char *buffer, size_t size, bool hardwareEUI=false);
return DevEUI as array of char
String getDevEui(bool hardwareEui=false);
return DevEUI as String
bool hardwareEui=false
: if true get DevEUI from Mac Address.
Check whether we have joined TTN
bool isJoined();
return true
if joined to TTN, false
if not.
Writes information about the device and LoRa module to Serial
.
void showStatus();
Will write something like:
---------------Status--------------
Device EUI: 004D22F44E5DXXXX
Application EUI: 70B3D57ED001XXXX
netid: 13
devaddr: 2601XXXX
NwkSKey: 6A2D3C24AD3C0D17614D7325BCXXXX
AppSKey: 9E68DCBEBF8AE9D891252FB7EXXXX
data rate: 5
tx power: 14dB
freq: 867100000Hz
-----------------------------------
Sets a function which will be called to process incoming messages. You'll want to do this in your setup()
function and then define a void (*cb)(const byte* payload, size_t length, port_t port)
function somewhere else in your sketch.
void onMessage(void (*cb)(const uint8_t *payload, size_t size, int rssi));
const uint8_t* payload
: Bytes received.size_t size
: Number of bytes.int rssi
: the rssi in dB.
See the [ttn-otaa]https://github.com/rgot-org/EzLoRaWAN/blob/main/examples/ttn-otaa/ttn-otaa.ino) example.
Activate the device via OTAA (default).
bool join();
bool join(const char *app_eui, const char *app_key, int8_t retries = -1, uint32_t retryDelay = 10000);
bool join(const char *dev_eui, const char *app_eui, const char *app_key, int8_t retries = -1, uint32_t retryDelay = 10000);
const char *app_eui
: Application EUI the device is registered to.const char *app_key
: Application Key assigned to the device.const char *dev_eui
: Device EUIint8_t retries = -1
: Number of times to retry after failed or unconfirmed join. Defaults to-1
which means infinite.uint32_t retryDelay = 10000
: Delay in ms between attempts. Defaults to 10 seconds.
Returns true
or false
depending on whether it received confirmation that the activation was successful before the maximum number of attempts.
Call the method without the first two arguments if the device's LoRa module is provisioned or comes with NVS stored values. See provision
, saveKeys
and restoreKeys
Activate the device via ABP.
bool personalize(const char *devAddr, const char *nwkSKey, const char *appSKey);
bool personalize();
const char *devAddr
: Device Address assigned to the device.const char *nwkSKey
: Network Session Key assigned to the device for identification.const char *appSKey
: Application Session Key assigned to the device for encryption.
Returns true
or false
depending on whether the activation was successful.
Call the method with no arguments if the device's LoRa module is provisioned or comes with NVS stored values. See provisionABP
, saveKeys
and restoreKeys
See the ttn_abp example.
Send a message to the application using raw bytes.
bool sendBytes(uint8_t *payload, size_t length, uint8_t port = 1, uint8_t confirm = 0);
uint8_t *payload
: Bytes to send.size_t length
: The number of bytes. Usesizeof(payload)
to get it.uint8_t port = 1
: The port to address. Defaults to1
.uint8_t confirm = false
: Whether to ask for confirmation. Defaults tofalse
Calls sendBytes()
with { 0x00 }
as payload to poll for incoming messages.
int8_t poll(uint8_t port = 1, uint8_t confirm = 0);
uint8_t port = 1
: The port to address. Defaults to1
.uint8_t confirm = 0
: Whether to ask for confirmation.
Returns the result of sendBytes()
.
Sets the informations needed to activate the device via OTAA, without actually activating. Call join() without the first 2 arguments to activate.
bool provision(const char *appEui, const char *appKey);
bool provision(const char *devEui, const char *appEui, const char *appKey);
const char *appEui
: Application Identifier for the device.const char *appKey
: Application Key assigned to the device.const char *devEui
: Device EUI.
Sets the informations needed to activate the device via ABP, without actually activating. call personalize()
without arguments to activate.
bool provisionABP(const char *devAddr, const char *nwkSKey, const char *appSKey);
const char *devAddr
: Device Address.const char *nwkSKey
: Network Session Key.const char *appSKey
: Application Session Key.
Save the provisioning keys (OTAA and ABP) in Non Volatile Storage (NVS).
bool saveKeys();
Restore the keys from NVS and provisioning the informations for OTAA or ABP connection. Call join()
or Personalize()
after this method to activate the device.
boobool restoreKeys(bool silent=true);
bool silent=true
: silent mode (no log)