Lesson 1: Build a Simple Arduino LoRa Node In 10 Minutes

Last Updated on 15 Sep 2017


Lately LoRaWAN has been increasingly popular in Internet of Things (IoT) applications. LoRaWAN offers low power, low payload Internet connection without using WIFI. It can run on a tiny coin cell battery for years. It is perfect for daily applications that require remote connection and monitoring but does not require high power or data bandwidth.

In LoRaWAN, LoRa end devices (also called LoRa nodes) gather useful data and transmits them to a network server using LoRa protocol. Usually LoRa nodes are embedded circuits with built-in LoRa technology with several sensors.

LoRa nodes are implemented in most low power wireless sensor network applications such as irrigation systems, smart metering, smart cities, smartphone detection, building automation, etc. There are a lot of industrial grade LoRa sensors available in the market, but in this tutorial, we will teach you how to build your own LoRa node!


In this tutorial, you will learn:

  • How to build and configure a LoRa Node using Cytron LoRa-RFM Shield + Arduino
  • How to create an account in The Things Network
  • How to add an application to your network
  • How to register your LoRa Node to the network
  • How to activate your LoRa Node


  1. Cytron LoRa-RFM Shield
  2. CT-UNO or other Arduino-compatible boards


  1. Arduino IDE


Build LoRa Node from zero

  1. The build is easy. Prepare CT-UNO (or other Arduino-compatible board).
  2. Plug the Cytron LoRa-RFM shield onto CT-UNO.
  3. Install the antenna.

That is all for the hardware setup. Next, we will setup its firmware yet. We are going to use the famous Arduino IDE to build firmware for it.

Arduino IDE basic setups for LoRa Node

  1. Install latest Arduino IDE from the link provided above.
  2. Open Arduino IDE. Now we are going to include necessarry libraries to build firmware for our LoRa node. First of all, download this ZIP file. Then in Arduino IDE, go to Sketch -> Include Library -> Add .ZIP library, select the downloaded ZIP file then open.
  3. Start a new sketch. Copy the code below and paste it into new sketch.
    #include <lmic.h>
    #include <hal/hal.h>
    #include <SPI.h>
    // LoRaWAN NwkSKey, network session key
    static const PROGMEM u1_t NWKSKEY[16] = { 0xAE, 0xBD, 0x9B, 0xBC, 0x43, 0x41, 0xFB, 0x47, 0x3D, 0xA5, 0x8D, 0x0D, 0x48, 0x98, 0xEF, 0xCF };
    // LoRaWAN AppSKey, application session key
    static const u1_t PROGMEM APPSKEY[16] = { 0xE1, 0x51, 0x0F, 0xB1, 0x59, 0x4C, 0xC8, 0xD7, 0xAA, 0x43, 0xAC, 0xE7, 0xE2, 0xBC, 0x5F, 0x1B };
    // LoRaWAN end-device address (DevAddr)
    static const u4_t DEVADDR = { 0x260314F7 };
    // These callbacks are only used in over-the-air activation, so they are
    // left empty here (we cannot leave them out completely unless
    // DISABLE_JOIN is set in config.h, otherwise the linker will complain).
    void os_getArtEui (u1_t* buf) { }
    void os_getDevEui (u1_t* buf) { }
    void os_getDevKey (u1_t* buf) { }
    static uint8_t mydata[] = "HI,Lora World!";
    static osjob_t sendjob;
    // Schedule data trasmission in every this many seconds (might become longer due to duty
    // cycle limitations).
    // we set 10 seconds interval
    const unsigned TX_INTERVAL = 10;
    // Pin mapping according to Cytron LoRa Shield RFM
    const lmic_pinmap lmic_pins = {
    	.nss = 10,
    	.rxtx = LMIC_UNUSED_PIN,
    	.rst = 7,
    	.dio = {2, 5, 6},
    void onEvent (ev_t ev) {
    	Serial.print(": ");
    	switch(ev) {
    		case EV_TXCOMPLETE:
    			Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
    			// Schedule next transmission
    			os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
    			Serial.println(F("Unknown event"));
    void do_send(osjob_t* j){
    	// Check if there is not a current TX/RX job running
    	if (LMIC.opmode & OP_TXRXPEND) {
    		Serial.println(F("OP_TXRXPEND, not sending"));
    	} else {
    		// Prepare upstream data transmission at the next possible time.
    		LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0);
    		Serial.println(F("Packet queued"));
    	// Next TX is scheduled after TX_COMPLETE event.
    void setup() {
    	// LMIC init
    	// Reset the MAC state. Session and pending data transfers will be discarded.
    	// Set static session parameters. Instead of dynamically establishing a session
    	// by joining the network, precomputed session parameters are be provided.
    	uint8_t appskey[sizeof(APPSKEY)];
    	uint8_t nwkskey[sizeof(NWKSKEY)];
    	memcpy_P(appskey, APPSKEY, sizeof(APPSKEY));
    	memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY));
    	LMIC_setSession (0x1, DEVADDR, nwkskey, appskey);
    	// Select frequencies range
    	// Disable link check validation
            // Disable ADR
    	// TTN uses SF9 for its RX2 window.
    	LMIC.dn2Dr = DR_SF9;
    	// Set data rate and transmit power for uplink (note: txpow seems to be ignored by the library)
    	// Start job
    void loop() {

We’ll need to come back to the Arduino code later, but first we need to register an account at The Things Network.

Create an Account at The Things Network (TTN):

We will be using The Things Network (TTN), one of the best free 3rd party network servers, to view and monitor our LoRa Node. The LoRa Node gathers information from sensors then transmits the data to the network server. All we need to do is create a TTN account and register our Lora Node as an application. After that, you will see the status of the LoRa node on our account’s overview page. As for how data is channelled to the TTN network server, this is the job of another LoRaWAN component – LoRa Gateway, which will be discussed in our next tutorial.Let’s start creating an account!

  1. Go to account.thethingsnetwork.org and click create an account. You will receive confirmation email to activate your account.
  2. Select CONSOLE from the top menu.
  3. Select APPLICATIONS to start registration of LoRa node.

Add an Application

Devices need to be registered with an application to communicate with. Let’s add one.

  1. On Applications page, click .
  2. The following screen will appear.
  3. For Application ID, choose a unique ID of lower case, alphanumeric characters and nonconsecutive – and _.
  4. For Description, enter anything you like.
  5. For Application EUI, we can leave it to let TTN generate for us.
  6. For Handler registration, we are going to use ttn-handler-brazil.
  7. Click Add application at the bottom of screen to finish.

You will be redirected to the newly added application.

Register your Device

You are now ready to register your device to the application.

  1. On the Applications > Your Application ID page, scroll down to DEVICES.
  2. In DEVICES category, click .
  3. You will come to the page as shown in the following.
  4. Device ID: For LoRaWAN applications, use lower case alphanumeric characters without consecutive – and _ .
  5. Device EUI: Leave empty so it will be randomly generated.
  6. App Key: Leave empty so it will be randomly generated.
  7. App EUI: Use the default settings.
  8. Click Register to finish. (You will be redirected to the newly registered device)

Activate your Device

In LoRaWAN, to secure the data traffic, each LoRa node will use “session keys” provided by the network server to encrypt the content of sent data. When the LoRa data packets reach the network server, the network server will use the session key to identify the owner of the LoRa node. This is also why we need to register our device to an account first.

There are 2 types of device activation, Over-The-Air Activation (OTAA) and Activation By Personalization (ABP).

  • OTAA – A secret key called App Key is generated upon device registration. It is used to request session keys from network server, where each request will result in different session key.
  • ABP – Session keys are fixed and have to be hard-coded into devices. In TTN, you set or generate the session keys via the console and hard-code them on your device. The device will use those keys forever for any data transmission until a different set of session keys is hard coded into them.

In this tutorial, we will be using ABP instead of OTAA.

  1. In the newly registered device page (Applications > Your Application ID > Devices > Your Device ID), choose Settings from menu located on top-right.
  2. Change activation method from OTAA to ABP
  3. At the same page, uncheck Frame Counter Checks box as well as shown in picture below to disable frame counter check for testing purpose.
  4. Click Save at the bottom of the page
  5. You will see 2 session keys generated for this device, Network Session Key and Application Session Key. These 2 keys will be used in Arduino Coding. (We said in ABP, session keys are fixed and have to be hard-coded into devices. Remember?)
  6. You can click on small eye icon in each keys to view the keys, initially they are hidden with dots.

Let’s back to Arduino

At this point, we are done with device registration. Let’s activate the device and get it up and running. There are 3 variables we need to change in Arduino coding: Network session keys, App session keys and Device address.

  1. Network Session Key (NWKSKEY). Press <> to show the msb hex decimal value. Copy and paste it into your arduino code.
  2. App Session Key (APPSKEY). Press <> to show the msb hex decimal value. Copy and paste it into your arduino code.
  3. Device Address (DEVADDR). Copy and paste the assigned device address to your arduino code, note that you need to add 0x in front.
  4. Below is the example:
  5. Click upload to upload the code to Arduino. Firmware is completed.

What else?

In the future, we will be monitoring the data of flow of LoRa Node in overview dashboard. Just go to Device page of each device, choose Data from top-menu from top-right corner and start viewing the data.

The example:

In the dashboard, hex code of each character will be displayed. Therefore, the sentence “HI,Lora World!” with total of 14 characters will be displayed in HEX format (14 HEX characters). ‘H’ as 0x48, ‘I’ as 0x49, ‘,’ as 0x2C, and so forth. You can visit this ascii table for reference.

Congratulations, you have built yourself first LoRa Node! To test its functionality, you are going to have a LoRa Gateway in your area and it is configure to forward LoRa packets to TTN network server. Let’s go to next tutorial Lesson 2: Setting up a Raspberry Pi 3 LoRa Gateway with HAT-LRGW-915 to build your own LoRa Gateway!

If you have any questions regarding to this tutorial, please kindly post them in our forum.


  1. The Things Network Documentations
  2. Arduino LoRaWAN library
  3. Arduino Source Code for LoRa Node

16 thoughts on “Lesson 1: Build a Simple Arduino LoRa Node In 10 Minutes”


    Hi i have some issue where my cytron shield node cannot connect to TTN the gatewasy setup already successful but not for the node any help would be much appreciated. Anyway i have follow every single detail

  2. Hi, I just receive Cytron LoRa-RFM Shield and Cytron Uno board and start to setup these two boards. However, I have some issues when compiling ttn-abp in Arduino IDE. The error message as follows:

    C:\Users\yw\AppData\Local\Temp\ccvU702n.ltrans0.ltrans.o: In function `radio_irq_handler’:
    C:\Users\yw\Documents\Arduino\libraries\arduino-lmic-master\src\lmic/radio.c:777: undefined reference to `table_get_u2′
    C:\Users\yw\AppData\Local\Temp\ccvU702n.ltrans0.ltrans.o: In function `schedRx12′:
    C:\Users\yw\Documents\Arduino\libraries\arduino-lmic-master\src\lmic/lmic.c:1910: undefined reference to `table_get_ostime’
    collect2.exe: error: ld returned 1 exit status
    exit status 1

    My arduino IDE versionis 1.8.13.
    I don’t know how to figure it out. Could you help?

  3. Is anyone attending to this forum from Cytron?
    I also have the same problem.
    21:15:25.523 -> Stats\Arduino\libraries\arduino-lmic-master\src\lmic\radio.c:689
    21:15:25.523 -> Starting
    21:15:25.523 -> FAILURE
    21:15:25.523 -> C:\Users\alexkoo\Documents\Arduino\libraries\arduino-lmic-master\src\lmic\radio.c:689

  4. may I know how to set the frequencies for the nodes?

    I am setting up a 1-Channel gateway:

    #elif _LFREQ==915
    int freqs [] = {
    // Uplink

  5. I was having problems when I connected the lora with the wifi shield data that she took from the lora could not be sent to blynk

  6. Hi,

    First of all I am sorry if my question sounded like not professional. I am trying to make Water Flow Sensor using the same hardware. When I use CT Uno it detects the sensor and show the output when there is a water flow. After i plug in the LoRa shield into CT Uno. It wont detect the sensor and the output wont change even there is a water flow. I have searched a lot of place for this problem. I use slot Digital no 2 on LoRa shield as a sensor. The other two cable is 5v and GND(beside 5v).

    Thanks in advance

  7. Hi, thanks a lot for this lesson! For the first time in a year I have been able to have a Arduino (Maduino board) reporting GPS location to the Things network !

  8. I have some error after compilation :


  9. We still need to have a LoRa gateway around which will forward data packets to TTN network server. This tutorial basically teaches on how to make a LoRa node only.

  10. How does the TTN get the data,you did not use any hardware for detecting the data send over air?

  11. Hello! I’m su hyun from Korea.

    First of all Thank you for your kind and great source.

    I had a problem when I did compile at arduino IDE.

    and error message was from libraries.

    I don’t know how to fix it, Could you please give me some advice about it?

    >> This is error message when I operate compile
    (I did all indication above, changing NWKSKEY, APPSKEY, DEVADDR)

    C:\Users\Administrator\Documents\Arduino\libraries\arduino-lmic-master\src\hal\hal.cpp: In function ‘void hal_printf_init()’:

    C:\Users\Administrator\Documents\Arduino\libraries\arduino-lmic-master\src\hal\hal.cpp:223:54: error: ‘_FDEV_SETUP_WRITE’ was not declared in this scope

    fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE);


    C:\Users\Administrator\Documents\Arduino\libraries\arduino-lmic-master\src\hal\hal.cpp:223:71: error: ‘fdev_setup_stream’ was not declared in this scope

    fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE);

Leave a Comment

Your email address will not be published.

Share this Tutorial

Share on facebook
Share on whatsapp
Share on email
Share on print
Share on twitter
Share on pinterest
Share on facebook
Share on whatsapp
Share on email
Share on print
Share on twitter
Share on pinterest

Latest Tutorial

DIY Digital Alarm Clock Using REKA:BIT With Micro:bit
Display Internet Time (NTP) on micro:bit
DIY Interactive Robot Using REKA:BIT With Micro:bit
BLTouch Installation for Ender 3 with 32-bit V4.2.2 Board
Pick and Send Random Meal’s Option and Locations through Telegram Bot Using Grove WiFi 8266 on micro:bit
Tutorials of Cytron Technologies Scroll to Top