How to build LoRa Based GPS Tracker Using ESP8266

LoRa Based GPS Tracker Using ESP8266

The LoRa technology penetration around the world is increasing and because of their ability to run on very minimal power, LoRa devices can be ideal for battery-intensive applications like remote weather monitoring, remote sensing, and tracking. We have earlier seen how we can integrate the HPD13A Lora Module with Arduino to Establish Communication with The Things Network and send temperature data onto the TTN Server.

In this project, we will be building a GPS Tracker using the Lora module HPD13A. Our aim will be to send live GPS Coordinates to The Things Network, as well as use Webhooks integrations available with The Things Network to get a visualization of the data.

Components Required

  • HPD13A LoRa Module
  • Neo 6M GPS Module
  • ESP8266 NodeMCU Dev Board
  • LM2596 Setup-down Converter.
  • Access To a LoRa Gateway Nearby

How does this LoRa GPS Tracker Project work?

We have discussed before how the LoRa technology is ideal for low-power applications. To connect any LoRa module with The Things Network, the primary requirement is a LoRa gateway nearby, if you have your own LoRa gateway, you can refer to our previous article on How To Configure a LoRa Gateway In India. You can also check the active LoRa Gateways in your vicinity from the Things Network Website: Once we’re sure that we have a working LoRa gateway in our vicinity, we can proceed with the project.

GPS Tracking Working

The working of this project is very simple, we have the ESP8266 acting as the main controller. The ESP8266 parses data from the Neo-6M GPS Module and converts the Latitude and Longitude into a LoRa Packet, this LoRa packet is then sent to the HPD13A LoRa module which connects to the nearby gateway. Once it is connected to a LoRa gateway, this LoRa packet gets sent to The Things Network. You can view this raw data on your Things Network Dashboard but for this project, we will create a webhook integration that will allow us to send the position data to Ubidots. Using this data on Ubidots, we can create a map interface to plot our tracking data.

ESP8266 LoRa GPS Tracker Circuit Diagram

GPS Tracker Circuit Diagram

The connections of this Nodemcu LoRa GPS Tracker are simple, we have used an LM2596 Step-Down Converter to take an input of range 9-12V from a Li-Po Battery and step it down to 4.2V to drive the ESP8266 and the Neo-6M GPS Module. The LoRa module will be driven by the 3.3V from the ESP8266 and will communicate via the SPI Pins.

Note: Since the Neo-6M is connected to the hardware serial pins of the ESP8266, you will have to keep the Neo-6M disconnected while uploading the code on the ESP8266.

Setup End Device on The Things Network

Let’s get started by Signing Up on The Things Network. You can create an individual or a student account, both of which are free of charge. When selecting the LoRa Cluster, you can select the EU Cluster if you’re not based in North America or Australia. Once you have created your account and completed the email verification, you will be able to access the TTN Console, which would look like this.

Things Network Dashboard

Click on create an application. Enter a unique application ID and application name and click on create.

Things Network Add Application

Once your application is created, click on the add end device.

Things Network Add End Device

Click on the “Manually” Tab, Enter the following parameters, generate the DevUI, AppEUI, and AppKey, and complete the end device creation.

Things Network Register End Device

Once the device is created, switch to the “Payload Formatters” Tab.

Things Network Payload Formatters Tab

Under the Formatters Type option select “Custom Javascript formatter” and paste the following code.

function Decoder(bytes, port) {
  var result = "";
  var result1 = "";
  var result2 = "";
  for (var i = 0; i < bytes.length; i++) {
    if(String.fromCharCode(bytes[i])=='X') {
    else {
      result += (String.fromCharCode(bytes[i]));
 var myArray = result.split(",");
 return {
   "position": { "value":1, "context":{"lat":result1.trim(),"lng":result2.trim()}} 

Things Network Payload Formatters Code

Our end device configuration on The Things network is done and we now move to burning the Arduino code.

Open the device overview and copy the DevUI, AppEUI, and the AppKey. Make sure that the LSB order is set for DevUI, AppEUI and the MSB order is set for AppKey.

Things Network Device Overview

Open the Arduino code attached and simply paste your IDs in their respective fields.

Arduino IDE

Once you upload the Arduino code, your device will start the LoRa transmission to The Things Network and this can be viewed in the “Live Data” Tab.

Things Network Live Data

Setting Up Ubidots Connection For Data Visualization

Now that we have our data coming to TTN, we will use the integration options to integrate a Ubidots Dashboard with this data. Since our data is primarily Latitude and Longitude Coordinates, we can use the Maps Widget offered by Ubidots. To get started, simply create a Ubidots STEM account and open your dashboard.

In the Devices Menu, select Plugins.

Ubidots Dashboard

Amongst the given options, we will search and select the “The Things Stack” option.

Ubidots Plugins

You can leave most of the settings to default and select the Ubidots Token as Default Token

Ubidots Token

Once you’ve added the name and description of your plug-in, click on create.

Ubidots Name and Description

Your plugin will now be live, we will now click on the edit plugin option.

Ubidots Plugin Edit

Under the decoder settings, we have the HTTPs Endpoint URL, this is the URL on which we will configure the TTN Server to send data packets, and copy the Plugin ID which is the portion of URL after the /api/webhook/ portion.

Ubidots Decoder Settings

Once this is done, scroll down to the Decoder Function panel and uncomment the following line of code.

var decoded_payload = args['uplink_message']['decoded_payload'];

Also, comment the following two lines.

let bytes =  Buffer.from(args['uplink_message']['frm_payload'], 'base64');
var decoded_payload = decodeUplink(bytes)['data'];

The changes would look similar to this.

Ubidots Decoding Function

Click on the Save & Make Live button. Our integration is now ready from the Ubidots side, before moving to TTN. We need to click on the API credentials option on our profile menu and copy the default token. This will be used later.

Ubidots API credentials

Open your TTN Application and on the Integrations panel, select Webhooks. And click on the Add Webhook button.

Things Network Webhooks

Amongst all the listed options, select the Ubidots plugin.

Things Network Ubidots plugin

You now need to enter your Plugin ID as mentioned above and your Ubidots Token.

Things Network Setup Webhooks for Ubidots

This will successfully create an integration webhook.

Things Network Webhooks Integration

Once this integration is done, our LoRa device will send data to the TTN Server which will automatically be directed to the Ubidots Server. You can open your Ubidots dashboard and under the Devices page, our device will become automatically visible.

Ubidots Server

We can now do the final step of adding a Map Widget on the dashboard. Under the Data Tab, Click on Dashboards to open your Dashboard. Click on the Create Widget Button.

Ubidots Map Widget

In the Add new Widget menu, you will see an option of Map, select it.

Ubidots Add Widget

Click on the Add Marker Group.

Ubidots Add Marker Group

Select your LoRa Device.

Ubidots LoRa Devices

Adjust the Map Trace settings according to your requirements and click on Save.

Ubidots Map Trace settings

That’s it! All the position data received from the LoRa device will now be visible on the map Widget in the form of a location marker. You can also add other widgets like tables for displaying raw coordinate values and the SNR (Signal to Noise Ratio).

Ubidots GPS Tracking

ESP8266 Lora GPS Tracker Working 

The below image shows the actual hardware and how the lattitue and longitude  value gets update on ubidots. Our Lora GPS tracker range actually depends on how much LoRa Gateway is present in the area. We will be able to send data to ubidots as long as there is a gateway within the reach of your LoRa module, in our case we had only one gateway set-up in our office (indoor) and we were able to cover only 2-3 km around the gateway. 

GPS Tracker Demo


#include <lmic.h>

#include <hal/hal.h>

#include <SPI.h>

#include <TinyGPSPlus.h>

TinyGPSPlus gps; String ProcData="Hello,World";


# define FILLMEIN 0


# warning "You must replace the values marked FILLMEIN with real values from the TTN control panel!"

# define FILLMEIN (#dont edit this, edit the lines that use FILLMEIN)


// This EUI must be in little-endian format, so least-significant-byte

// first. When copying an EUI from ttnctl output, this means to reverse // the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3,

// 0x70. static const u1_t PROGMEM APPEUI[8]= {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8);}

// This should also be in little endian format, see above.

static const u1_t PROGMEM DEVEUI[8]= {0x36, 0x52, 0x05, 0xD0, 0x7E, 0xD5, 0xB3, 0x70};

void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);}

// This key should be in big endian format (or, since it is not really a

// number but a block of memory, endianness does not really apply). In

// practice, a key taken from ttnctl can be copied as-is.

static const u1_t PROGMEM APPKEY[16] = {0x97, 0x7B, 0x4B, 0xA3, 0x9A, 0x8D, 0x33, 0x5E, 0x42, 0x13, 0x9C, 0x6B, 0xE9, 0xF9, 0x5E, 0xE1};

void os_getDevKey (u1_t* buf) { memcpy_P(buf, APPKEY, 16);}

uint8_t mydata[25] ;

static osjob_t sendjob;

// Schedule TX every this many seconds (might become longer due to duty

// cycle limitations). const unsigned TX_INTERVAL = 2;

// Pin mapping

const lmic_pinmap lmic_pins = {

 .nss = 15,


 .rst = 16,

 .dio = {5, 4, LMIC_UNUSED_PIN},


void printHex2(unsigned v) {

 v &= 0xff;

 if (v < 16)


 Serial1.print(v, HEX);


void onEvent (ev_t ev) {


 Serial1.print(": ");

 switch(ev) {

  case EV_SCAN_TIMEOUT:     Serial1.println(F("EV_SCAN_TIMEOUT"));


  case EV_BEACON_FOUND: Serial1.println(F("EV_BEACON_FOUND"));


  case EV_BEACON_MISSED: Serial1.println(F("EV_BEACON_MISSED"));


  case EV_BEACON_TRACKED: Serial1.println(F("EV_BEACON_TRACKED"));


  case EV_JOINING: Serial1.println(F("EV_JOINING"));


  case EV_JOINED: Serial1.println(F("EV_JOINED")); {

   u4_t netid = 0; devaddr_t devaddr = 0;

   u1_t nwkKey[16];

   u1_t artKey[16];

   LMIC_getSessionKeys(&netid, &devaddr, nwkKey, artKey);

   Serial1.print("netid: ");

   Serial1.println(netid, DEC);

   Serial1.print("devaddr: ");

   Serial1.println(devaddr, HEX);

   Serial1.print("AppSKey: ");

   for (size_t i=0; i<sizeof(artKey); ++i) {

    if (i != 0) Serial1.print("-");




  Serial1.print("NwkSKey: ");

  for (size_t i=0; i<sizeof(nwkKey); ++i) {

   if (i != 0) Serial1.print("-");



  Serial1.println(); }

// Disable link check validation (automatically enabled

// during join, but because slow data rates change max TX

// size, we don't use it in this example. LMIC_setLinkCheckMode(0); break;

/* || This event is defined but not used in the code. No || point in wasting codespace on it. || || case EV_RFU1: || Serial1.println(F("EV_RFU1")); || break; */

case EV_JOIN_FAILED: Serial1.println(F("EV_JOIN_FAILED"));


case EV_REJOIN_FAILED: Serial1.println(F("EV_REJOIN_FAILED"));


case EV_TXCOMPLETE: Serial1.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));

if (LMIC.txrxFlags & TXRX_ACK) Serial1.println(F("Received ack"));

if (LMIC.dataLen) {

Serial1.print(F("Received "));

Serial1.print(LMIC.dataLen); Serial1.println(F(" bytes of payload"));


// Schedule next transmission

os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);


case EV_LOST_TSYNC: Serial1.println(F("EV_LOST_TSYNC"));


case EV_RESET: Serial1.println(F("EV_RESET"));


case EV_RXCOMPLETE: // data received in ping slot Serial1.println(F("EV_RXCOMPLETE"));


case EV_LINK_DEAD: Serial1.println(F("EV_LINK_DEAD"));


case EV_LINK_ALIVE: Serial1.println(F("EV_LINK_ALIVE")); break;

/* || This event is defined but not used in the code. No || point in wasting codespace on it. || || case EV_SCAN_FOUND: || Serial1.println(F("EV_SCAN_FOUND")); || break; */

case EV_TXSTART: Serial1.println(F("EV_TXSTART"));


case EV_TXCANCELED: Serial1.println(F("EV_TXCANCELED"));


case EV_RXSTART: /* do not print anything -- it wrecks timing */


case EV_JOIN_TXCOMPLETE: Serial1.println(F("EV_JOIN_TXCOMPLETE: no JoinAccept"));


default: Serial1.print(F("Unknown event: "));

Serial1.println((unsigned) ev);




void do_send(osjob_t* j){

// Check if there is not a current TX/RX job running

if (LMIC.opmode & OP_TXRXPEND) {

Serial1.println(F("OP_TXRXPEND, not sending"));


else {

// Prepare upstream data transmission at the next possible

time. unsigned long start = millis();

do {

while (Serial.available())



while (millis() - start < 1000);


float flon=gps.location.lng();

char charLat[20];

char charLong[20];

Serial1.print("Cords: ");

Serial1.print(flat); Serial1.print(" , ");


dtostrf(flat, 10, 7, charLat);

dtostrf(flon, 10, 7, charLong);

sprintf((char *)mydata, "%s,%sX", charLat,charLong);

LMIC_setTxData2(1, mydata,25, 0);

Serial1.println(F("Packet queued"));

//int x=ProcData.length();

//ProcData.toCharArray((char *)mydata,sizeof(mydata));


// Next TX is scheduled after TX_COMPLETE event.


void setup() {




// LMIC init os_init();

// Reset the MAC state. Session and pending data transfers will be discarded. LMIC_reset(); LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);

// Start job (sending automatically starts OTAA too) do_send(&sendjob);


void loop() {




I not to mention my pals appeared to be looking through the great techniques from your site while quickly came up with an awful feeling I had not thanked the web blog owner for them. All the women were definitely totally very interested to read through all of them and now have actually been tapping into these things. I appreciate you for getting well helpful and then for deciding on some outstanding ideas millions of individuals are really desperate to learn about. My personal sincere regret for not expressing gratitude to earlier.

My wife and i were absolutely comfortable that Michael could complete his analysis because of the ideas he made in your web page. It's not at all simplistic to just continually be releasing concepts which usually other people may have been trying to sell. And now we understand we need the writer to thank for that. The illustrations you've made, the straightforward blog navigation, the relationships your site help to promote - it's most fantastic, and it is facilitating our son in addition to the family imagine that that matter is excellent, which is certainly pretty vital. Thanks for the whole thing!

Thank you for your whole effort on this web page. Betty take interest in managing investigations and it is obvious why. Most people notice all concerning the lively mode you produce helpful tactics by means of the web site and as well as welcome response from website visitors on this idea then our favorite girl is always understanding a lot of things. Take advantage of the remaining portion of the new year. You are always performing a good job.

A lot of thanks for your whole efforts on this website. Kim really likes going through research and it's simple to grasp why. Almost all notice all about the powerful tactic you render advantageous guides through your website and even increase contribution from other individuals on that concern then our princess is undoubtedly learning a lot of things. Enjoy the rest of the year. You are doing a really great job.

I and also my guys were found to be studying the best recommendations from your site and so instantly I got an awful feeling I had not thanked you for those strategies. All of the men are already as a result thrilled to study them and have in effect simply been loving them. We appreciate you actually being quite thoughtful and also for deciding upon this sort of outstanding subjects most people are really eager to know about. My honest regret for not expressing gratitude to you earlier.

Thank you so much for providing individuals with an exceptionally pleasant chance to read critical reviews from this blog. It's always very terrific and also packed with amusement for me personally and my office friends to visit the blog at least 3 times in one week to find out the newest items you have got. Of course, we're actually contented with your magnificent opinions served by you. Some 2 ideas in this posting are easily the most efficient I've ever had.

I simply wished to thank you so much once again. I'm not certain what I would have carried out in the absence of the actual information contributed by you over this concern. It truly was a real difficult situation in my opinion, but coming across this expert mode you processed it made me to jump over fulfillment. Now i am grateful for your advice and thus have high hopes you find out what an amazing job you happen to be getting into educating the others all through your web blog. More than likely you have never met all of us.

Thanks for all your hard work on this web page. Debby really likes getting into investigation and it's easy to understand why. Most of us notice all regarding the powerful ways you render advantageous tactics by means of this website and as well recommend participation from the others on the area of interest and our own princess is undoubtedly discovering a lot of things. Have fun with the rest of the year. Your performing a very good job.

I would like to voice my affection for your kind-heartedness supporting individuals that really want help on this topic. Your real commitment to passing the message all over was astonishingly insightful and has frequently made ladies much like me to arrive at their aims. The useful hints and tips indicates a whole lot a person like me and even further to my peers. Thanks a lot; from everyone of us.

I simply needed to thank you very much again. I do not know what I would've taken care of without the type of opinions revealed by you about such a concern. It absolutely was a very hard circumstance in my view, however , being able to see the skilled technique you processed the issue forced me to jump for fulfillment. I'm thankful for this advice as well as trust you are aware of a great job you have been carrying out teaching many people using your website. I am sure you've never come across all of us.

Thank you for all your work on this website. Gloria really likes getting into research and it's really obvious why. We know all concerning the lively way you give both useful and interesting techniques via the website and boost contribution from the others on this issue plus our favorite princess is really becoming educated a great deal. Have fun with the remaining portion of the new year. You're the one carrying out a superb job.

I needed to compose you the little bit of remark just to thank you so much again about the pleasing methods you've discussed on this page. It has been so remarkably generous of people like you to supply extensively all that most of us might have sold as an e book to end up making some bucks on their own, notably given that you could possibly have tried it in the event you considered necessary. Those pointers also worked to become easy way to fully grasp other people have similar keenness much like my personal own to find out great deal more on the topic of this matter. I think there are some more enjoyable instances in the future for those who read your site.

I must express my admiration for your generosity for those who should have help with this particular area. Your personal commitment to passing the message all over turned out to be remarkably advantageous and have continually permitted women much like me to reach their desired goals. This useful advice implies a lot a person like me and additionally to my mates. Many thanks; from each one of us.

Add new comment

The content of this field is kept private and will not be shown publicly.

Plain text

  • No HTML tags allowed.
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.