LoRa Mesh Networking with Simple Arduino-Based Modules

Project source code at GitHub: lora-mesh

In this project, I will show you how I built a mesh network of 4 Arduino-Based LoRa modules and devised a way to visualize the network’s behavior in realtime. Using a realtime visualization we can see how the network forms and how it heals itself when network nodes become unreachable.

By now you’ve probably heard of LoRa (“long range”) radio technology. It is intended for reliable communication of small amounts of data over long distances (several kilometers). It’s also geared toward low power applications. LoRa modules are relatively cheap (about $8 for a bare module), but the easiest way to use LoRa is to buy development boards that also have a microcontroller on them, like the Moteino.

LoRa radios can be used for point-to-point communication, and can also be used in a LoRaWAN network which involves communication with a centralized base station. This article, however, discusses a different approach: mesh networking of LoRa nodes. Mesh networking is a network topology where nodes communicate with one another either directly (if they are in range) or indirectly via intermediate nodes. For example, if node 1 wants to send a message to node 2, but is too far away from node 2, the message will automatically be routed via an intermediate node that is in range, say Node 3.

In fact, the path may involve several intermediate nodes. The discovery of the route from 1 to 2 is handled by a mesh networking layer — your application code doesn’t need to know anything about the routing. With mesh networking, LoRa nodes can be spread out across a further distance but can still communicate with one another as long as there is some connectivity between nodes in the mesh. Every node can talk to every other node, even though the network is only partially connected. Sound familiar? This is pretty much the architecture of the Internet. The robustness lies with the ability to route around damage and find new routes.

Mesh Networking in Arduino Code

How do we accomplish mesh networking with simple LoRa radios? If you have used LoRa radios before, you probably used the RadioHead library. We will use it in this project, too, because it includes an implementation of mesh networking. For details on how the mesh works, see the RadioHead documentation about it. I wrote an Arduino sketch to run on each of 4 Moteino boards so that each node will form a part of the network. Each node has an identity (e.g. “2”) which is stored in the device EEPROM.

First a note about the difficulty of testing mesh networks. It’s hard to place the nodes in such a way that only some nodes can communicate directly. To do so, I’d have to put my nodes far apart all over my neighborhood. Lucky, the RadioHead library has several test networks defined so that you can force some nodes to not be able to communicate. When a test network is defined, the RadioHead library simply ignores messages is receives from nodes it is not supposed to be able to hear. This lets us test much more easily. I’m using test network #3 which is defined in the library like this:

  // This network looks like 1-2-4
  //                         |   |
  //                         --3--

That is, nodes 1 and 4 cannot communicate with one another directly, and nodes 2 and 3 cannot communicate with one another directly. This will become very evident in the visualization.

Each node attempts to communicate with every other node in the network, and in the process it keeps track of a routing table that describes which nodes it can talk to directly and which nodes that messages get routed through when there is no direct connection available. It also keeps track of the signal strength that it “hears” from a node when it communicates with it directly. The result is that each node has a data structure with this info. Here is a sample routing table (expressed in JSON) for node 2:

{"2": [{"n":1,"r":-68}, {"n":255,"r":0}, {"n":1,"r":0}, {"n":0,"r":0}]}

The data has an array of 4 records, one for each node in the network. The 4 records above represent the routing info for this node (2) communicating with nodes 1, 2, 3, and 4 respectively. Each record has two properties. Propery “n” is the identity of the node that node 2 must talk to in order to communicate with the node in this position of the table. Record number 1 {"n":1,"r":-68} means that node 2 can talk to node 1 via node 1. That is, it has successfully communicated directly with node 1 and the signal strength indicated by the “r” property is -68 dBm.

Record 2 {"n":255,"r":0} has an “n” value of 255 which means “self”, so we can ignore this record. Record 3 {"n":1,"r":0} means that node 2 must communicate with node 3 via node 1 because there is no direct communication (which is why the RSSI value is 0). Record 4 {"n":0,"r":0} has a “n” property of 0 which means that node 2 has not yet discovered a way to talk to node 4. This may because it has not tried yet, or perhaps node 4 has dropped out of the network and nobody can find it.

Over time, by attempting to send messages to every other node, each node builds up this information about who it can talk to and how its messages are being routed, as well as the signal strength that it “hears” from any node it successfully communicates directly with. The information sent in messages is the node’s routing table itself. That is why we represent the routing table as a JSON string and use abbreviated property names. We want the message to be short.

Visualizing the Mesh Network

In order to display the network in a web page, we need to get all the routing information from each node. One of the LoRa nodes in my network (node 1) is connected to the Internet by connecting the Moteino board to an IoT Experimenter board. The IoT Experimenter is a simple ESP8266 development board I built to help with my IoT projects. It serves as a gateway to the Internet for this project. When node 1 receives a routing table from another node, it writes the JSON data over serial to the ESP8266 gateway code. The gateway writes the record to an MQTT topic. Over time, the routing table from each node is written to the topic and updated as the info changes.

Now we need a way for this information to be displayed on a web page. I wrote a Node.js server that subscribes to the MQTT topic and writes the info over a websocket to a web client using Socket.IO. The graphics are created using p5.js which is an easy way to draw impressive graphics on a web page canvas.

A solid line between 2 nodes means there is direct communication. The color of the line matches the node that is making the observation, and the number is the signal strength that the node “hears” from the other node. So below we can see that node 1 and 2 are directly able to communicate and that node 1 is receiving from node 2 with an RSSI value of -63 dBm and node 2 receives from node 1 with an RSSI of -64 dBm. The distance between nodes is proportional to the signal strength — you can see that node 4 is further away from the other nodes.

Lines with dots indicate indirect communication, for example, the lines between nodes 1 and 4 mean that they are communicating indirectly. The yellow dots on the red line mean that node 1 is communicating with node 4 via node 2 (which is yellow). The blue dots on the green line mean that node 4 is communicating with node 1 via node 3. Note that the communication between nodes 2 and 3 have red dots, meaning that node 1 is serving as the intermediary for these nodes.

Formation/Healing of a Mesh Network

Let’s see the visualization in action! This video shows the formation of a network when I connect power to the nodes. In the video I remove power from one of the nodes serving as an intermediary in the mesh and we can see how the network heals itself by finding new routes.

Get the Code

All the source code for this project is available on GitHub: nootropic design lora-mesh project.
It includes info on how to use this code yourself if you are interested.

Published by Michael, on October 20th, 2018 at 4:09 pm. Filed under: IoT,LoRa. | 20 Comments |

20 Responses to “LoRa Mesh Networking with Simple Arduino-Based Modules”

  1. hey love project, trying build farm mesh network, long range, to monitor water for sheep, would this code work with esp32 with sx1276 built in

    Comment by Luke on February 8, 2019 at 5:43 PM

  2. It should work with an ESP32 microcontroller as long as there is also a LoRa transceiver. The RadioHead library does seem to support the ESP32.

    Comment by Michael on February 9, 2019 at 9:24 AM

  3. Cool project, I’m trying to replicate it as well but I only have 2 LoRa Transceivers.
    I managed to initialize void setup() but can’t get the loop to work..
    I tried putting some identifiers on which line of arduino code I am at..
    I keep getting stuck at this piece of code from void loop():
    “uint8_t error = manager->sendtoWait((uint8_t *)buf, strlen(buf), n);”
    trying to print “error” but seems like it just won’t show up on the Serial Monitor

    Comment by Joshua on February 12, 2019 at 8:10 AM

  4. Strange, it should return eventually. Did you set the nodeID of each module using the SetNodeId sketch?

    Comment by Anonymous on February 12, 2019 at 8:35 AM

  5. Yes I did use the SetNodeId sketch and set it to 1 and 2 respectively for the 2 LoRa modules that I have.
    I also set the N_NODES 2 for the LoRaMesh sketch

    Comment by Joshua on February 12, 2019 at 10:12 AM

  6. Hello I have some
    Heltec Wifi LoRa 32 – ESP32 with OLED
    And try to get it running for days.

    I have got many problems.

    Is a projeckt known where to go with ESP32 all in one

    Comment by Torsten on February 17, 2019 at 7:36 AM

  7. This project uses the HopeRF RFM95W LoRa radio and the RadioHead library. I do not know if different hardware will work.

    Comment by Michael on February 17, 2019 at 7:55 AM

  8. I looked around for ages for somebody that managed to build a mesh network with lora transceivers. Super amazing that you managed this. No pressure, but if you would be willing to answer some of my projects specific questions, please shoot me an email. It’s a little too long for a comment. I don’t even mind compensating your time. Respect again for your achievements. Really cool stuff

    Comment by Jan Willem Kolkman on February 25, 2019 at 6:05 PM

  9. hello, I’m replicating it with some differences I use the esp32 connected by serial port with mega 2560, the mega 2560 has a module lora wifi rfm95 dragino with gps. the gps has not made it work yet. the node.js upload it to a raspberry and the broker configures it in https://api.cloudmqtt.com. the web client charges it and shows me a blank page, I only have two modules working, they are programmed and configured. help help, the broker shows socket error when the esp32 connects.

    Comment by victor on March 21, 2019 at 9:23 PM

  10. Hello, I have managed to replicate the project, I have modified it to use node mcu 32s. in my replica I use dragons and two gas sensors. my question is how could I use the gps data and the measurements of the sensors to display them on the same page using the same node.js, with the gps points on a map, sorry for my poor english

    Comment by victor on April 1, 2019 at 6:09 PM

  11. Yes, I think you could. You would need to send the GPS coordinates in the LoRa messages. And you would need to find an HTML/JS map component to put on the web page to plot the points. I have not done that, though.

    Comment by Michael on April 3, 2019 at 7:24 PM

  12. Hi,

    Will this work with Semtech SX1276 module?

    Comment by Priti Rathi on April 3, 2019 at 8:22 AM

  13. Yes, that is the only LoRa chipset. My HopeRF modules have the SX1276 chip on them.

    Comment by Michael on April 3, 2019 at 7:23 PM

  14. Used shield dragino lora gps with arduino mega 2560are nodes

    Comment by Victor on April 3, 2019 at 6:03 PM

  15. Hi,

    I am trying to replicate the project. Do you have any example test code that I can use?

    Comment by Priti Rathi on April 18, 2019 at 9:01 AM

  16. The very first line of the article points you to the source code.

    Comment by Michael on April 18, 2019 at 9:36 AM

  17. Thanks for replying Michael. But the source code is not working for me. I am using LoRa SX1276 NiceRF modules. The send2wait is returning no route as error.
    Do I need to include the addRouteTo() function in the Arduino Code as well. I can see it is there in the RHRouter class file.
    Is there any changes need to be done in the code?

    Comment by Priti Rathi on April 19, 2019 at 6:41 AM

  18. I did this project with HopeRF modules. I don’t know if the RadioHead library works for NiceRF modules. If you want to use a test network, then yes you need to uncomment one of the network topologies. The article explains this.

    Comment by Michael on April 19, 2019 at 9:33 AM

  19. Also I see, the sample test networks RH_MESH_TEST_NETWORKS are commented. Do I need to comment out one of them?

    Comment by Priti Rathi on April 19, 2019 at 9:24 AM

  20. Hi Michael,
    Thanks for replying. So apart from the network topology option anything else do I need to uncomment in the code?
    Sorry I am asking a lot of basic questions here. But your responses means a lot cause I am kinda stuck in here.

    Comment by Priti Rathi on April 22, 2019 at 2:17 AM

Leave a Reply